Skip to content

Commit 3db38e6

Browse files
committed
支持更新 token 中的 claims 数据
1 parent 1226b60 commit 3db38e6

File tree

7 files changed

+119
-23
lines changed

7 files changed

+119
-23
lines changed

internal/ratelimit/mocks/ratelimit.mock.go

Lines changed: 7 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

session/global.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,7 @@ func CheckLoginMiddleware() gin.HandlerFunc {
4949
func RenewAccessToken(ctx *gctx.Context) error {
5050
return defaultProvider.RenewAccessToken(ctx)
5151
}
52+
53+
func UpdateClaims(ctx *gctx.Context, claims Claims) error {
54+
return defaultProvider.UpdateClaims(ctx, claims)
55+
}

session/memory.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ package session
1717
import (
1818
"context"
1919

20+
"github.com/ecodeclub/ginx/gctx"
21+
2022
"github.com/ecodeclub/ekit"
2123
"github.com/ecodeclub/ginx/internal/errs"
2224
)
@@ -33,6 +35,10 @@ func (m *MemorySession) Destroy(ctx context.Context) error {
3335
return nil
3436
}
3537

38+
func (m *MemorySession) UpdateClaims(ctx *gctx.Context, claims Claims) error {
39+
return nil
40+
}
41+
3642
func (m *MemorySession) Del(ctx context.Context, key string) error {
3743
delete(m.data, key)
3844
return nil

session/provider.mock_test.go

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

session/redis/provider.go

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ var (
3434

3535
var _ session.Provider = &SessionProvider{}
3636

37-
// SessionProvider 默认是预加载机制,即 Get 的时候会顺便把所有的数据都拿过来
38-
// 默认情况下,产生的 Session 对应了两个 token,access token 和 refresh token
37+
// SessionProvider 默认情况下,产生的 Session 对应了两个 token,
38+
// access token 和 refresh token
3939
// 它们会被放进去 http.Response x-access-token 和 x-refresh-token 里面
4040
// 后续前端发送请求的时候,需要把 token 放到 Authorization 中,以 Bearer 的形式传过来
4141
// 很多字段并没有暴露,如果你需要自定义,可以发 issue
@@ -49,6 +49,21 @@ type SessionProvider struct {
4949
expiration time.Duration
5050
}
5151

52+
// UpdateClaims 在这个实现里面,claims 同时写进去了
53+
func (rsp *SessionProvider) UpdateClaims(ctx *gctx.Context, claims session.Claims) error {
54+
accessToken, err := rsp.m.GenerateAccessToken(claims)
55+
if err != nil {
56+
return err
57+
}
58+
refreshToken, err := rsp.m.GenerateRefreshToken(claims)
59+
if err != nil {
60+
return err
61+
}
62+
ctx.Header(rsp.atHeader, accessToken)
63+
ctx.Header(rsp.rtHeader, refreshToken)
64+
return nil
65+
}
66+
5267
func (rsp *SessionProvider) RenewAccessToken(ctx *ginx.Context) error {
5368
// 此时这里应该放着 RefreshToken
5469
rt := rsp.extractTokenString(ctx)

session/redis/provider_test.go

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,67 @@ func (s *ProviderTestSuite) TestRenewSession() {
6464
require.NoError(s.T(), err)
6565
}
6666

67+
func TestSessionProvider_UpdateClaims(t *testing.T) {
68+
testCases := []struct {
69+
name string
70+
mock func(ctrl *gomock.Controller) redis.Cmdable
71+
wantErr error
72+
}{
73+
{
74+
name: "更新成功",
75+
mock: func(ctrl *gomock.Controller) redis.Cmdable {
76+
cmd := mocks.NewMockCmdable(ctrl)
77+
pip := mocks.NewMockPipeliner(ctrl)
78+
pip.EXPECT().HMSet(gomock.Any(), gomock.Any(), gomock.Any()).
79+
AnyTimes().Return(nil)
80+
pip.EXPECT().Expire(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil)
81+
pip.EXPECT().Exec(gomock.Any()).Return(nil, nil)
82+
cmd.EXPECT().Pipeline().Return(pip)
83+
return cmd
84+
},
85+
},
86+
}
87+
for _, tc := range testCases {
88+
t.Run(tc.name, func(t *testing.T) {
89+
ctrl := gomock.NewController(t)
90+
defer ctrl.Finish()
91+
client := tc.mock(ctrl)
92+
sp := NewSessionProvider(client, "123")
93+
recorder := httptest.NewRecorder()
94+
95+
ctx, _ := gin.CreateTestContext(recorder)
96+
// 先创建一个
97+
_, err := sp.NewSession(&gctx.Context{
98+
Context: ctx,
99+
}, 123, map[string]string{"hello": "world"}, map[string]any{})
100+
101+
gtx := &gctx.Context{
102+
Context: ctx,
103+
}
104+
newCl := session.Claims{
105+
Uid: 234,
106+
SSID: "ssid_123",
107+
Data: map[string]string{"hello": "nihao"}}
108+
109+
err = sp.UpdateClaims(gtx, newCl)
110+
assert.Equal(t, tc.wantErr, err)
111+
if err != nil {
112+
return
113+
}
114+
token := ctx.Writer.Header().Get("X-Access-Token")
115+
rc, err := sp.m.VerifyAccessToken(token)
116+
require.NoError(t, err)
117+
cl := rc.Data
118+
assert.Equal(t, newCl, cl)
119+
token = ctx.Writer.Header().Get("X-Refresh-Token")
120+
rc, err = sp.m.VerifyAccessToken(token)
121+
require.NoError(t, err)
122+
cl = rc.Data
123+
assert.Equal(t, newCl, cl)
124+
})
125+
}
126+
}
127+
67128
func TestProvider(t *testing.T) {
68129
suite.Run(t, new(ProviderTestSuite))
69130
}
@@ -101,8 +162,7 @@ func TestSessionProvider_NewSession(t *testing.T) {
101162
ctx, _ := gin.CreateTestContext(recorder)
102163
sess, err := sp.NewSession(&gctx.Context{
103164
Context: ctx,
104-
}, 123,
105-
map[string]string{"hello": "world"}, map[string]any{})
165+
}, 123, map[string]string{"hello": "world"}, map[string]any{})
106166
assert.Equal(t, tc.wantErr, err)
107167
if err != nil {
108168
return

session/types.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ type Session interface {
3838

3939
// Provider 定义了 Session 的整个管理机制。
4040
// 所有的 Session 都必须支持 jwt
41+
//
42+
//go:generate mockgen -source=./types.go -destination=./provider.mock_test.go -package=session Provider
4143
type Provider interface {
4244
// NewSession 将会初始化 Session
4345
// 其中 jwtData 将编码进去 jwt 中
@@ -49,6 +51,11 @@ type Provider interface {
4951
// 也就是,用户可以预期拿到的 Session 永远是没有过期,直接可用的
5052
Get(ctx *gctx.Context) (Session, error)
5153

54+
// UpdateClaims 修改 claims 的数据
55+
// 但是因为 jwt 本身是不可变的,所以实际上这里是重新生成了一个 jwt 的 token
56+
// 必须传入正确的 SSID
57+
UpdateClaims(ctx *gctx.Context, claims Claims) error
58+
5259
// RenewAccessToken 刷新并且返回一个新的 access token
5360
// 这个过程会校验长 token 的合法性
5461
RenewAccessToken(ctx *gctx.Context) error

0 commit comments

Comments
 (0)