-
Notifications
You must be signed in to change notification settings - Fork 13
实现 JWT 一键支持 #8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
实现 JWT 一键支持 #8
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| package jwt | ||
|
|
||
| import ( | ||
| "time" | ||
|
|
||
| "github.com/ecodeclub/ekit/bean/option" | ||
| "github.com/golang-jwt/jwt/v5" | ||
| ) | ||
|
|
||
| type RegisteredClaims[T any] struct { | ||
| Data T `json:"data"` | ||
| jwt.RegisteredClaims | ||
| } | ||
|
|
||
| type Options struct { | ||
| Expire time.Duration // 有效期 | ||
| EncryptionKey string // 加密密钥 | ||
| DecryptKey string // 解密密钥 | ||
| Method jwt.SigningMethod // 签名方式 | ||
| Issuer string // 签发人 | ||
| genIDFn func() string // 生成 JWT ID (jti) 的函数 | ||
| } | ||
|
|
||
| // NewOptions 定义一个 JWT 配置. | ||
| // DecryptKey: 默认与 EncryptionKey 相同. | ||
| // Method: 默认使用 jwt.SigningMethodHS256 签名方式. | ||
| func NewOptions(expire time.Duration, encryptionKey string, | ||
| opts ...option.Option[Options]) *Options { | ||
| dOpts := Options{ | ||
| Expire: expire, | ||
| EncryptionKey: encryptionKey, | ||
| DecryptKey: encryptionKey, | ||
| Method: jwt.SigningMethodHS256, | ||
| genIDFn: func() string { return "" }, | ||
| } | ||
|
|
||
| option.Apply[Options](&dOpts, opts...) | ||
|
|
||
| return &dOpts | ||
| } | ||
|
|
||
| // WithDecryptKey 设置解密密钥. | ||
| func WithDecryptKey(decryptKey string) option.Option[Options] { | ||
| return func(o *Options) { | ||
| o.DecryptKey = decryptKey | ||
| } | ||
| } | ||
|
|
||
| // WithMethod 设置 JWT 的签名方法. | ||
| func WithMethod(method jwt.SigningMethod) option.Option[Options] { | ||
| return func(o *Options) { | ||
| o.Method = method | ||
| } | ||
| } | ||
|
|
||
| // WithIssuer 设置签发人. | ||
| func WithIssuer(issuer string) option.Option[Options] { | ||
| return func(o *Options) { | ||
| o.Issuer = issuer | ||
| } | ||
| } | ||
|
|
||
| // WithGenIDFunc 设置生成 JWT ID 的函数. | ||
| // 可以设置成 WithGenIDFunc(uuid.NewString). | ||
| func WithGenIDFunc(fn func() string) option.Option[Options] { | ||
| return func(o *Options) { | ||
| o.genIDFn = fn | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,184 @@ | ||
| package jwt | ||
|
|
||
| import ( | ||
| "testing" | ||
| "time" | ||
|
|
||
| "github.com/ecodeclub/ekit/bean/option" | ||
| "github.com/golang-jwt/jwt/v5" | ||
| "github.com/stretchr/testify/assert" | ||
| ) | ||
|
|
||
| func TestNewOptions(t *testing.T) { | ||
| var genIDFn func() string | ||
| tests := []struct { | ||
| name string | ||
| expire time.Duration | ||
| encryptionKey string | ||
| want *Options | ||
| }{ | ||
| { | ||
| name: "normal", | ||
| expire: 10 * time.Minute, | ||
| encryptionKey: "sign key", | ||
| want: &Options{ | ||
| Expire: 10 * time.Minute, | ||
| EncryptionKey: "sign key", | ||
| DecryptKey: "sign key", | ||
| Method: jwt.SigningMethodHS256, | ||
| genIDFn: genIDFn, | ||
| }, | ||
| }, | ||
| } | ||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| got := NewOptions(tt.expire, tt.encryptionKey) | ||
| got.genIDFn = genIDFn | ||
| assert.Equal(t, tt.want, got) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestWithDecryptKey(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| fn func() option.Option[Options] | ||
| want string | ||
| }{ | ||
| { | ||
| name: "normal", | ||
| fn: func() option.Option[Options] { | ||
| return nil | ||
| }, | ||
| want: encryptionKey, | ||
| }, | ||
| { | ||
| name: "set_another_key", | ||
| fn: func() option.Option[Options] { | ||
| return WithDecryptKey("another sign key") | ||
| }, | ||
| want: "another sign key", | ||
| }, | ||
| } | ||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| var got string | ||
| if tt.fn() == nil { | ||
| got = NewOptions(defaultExpire, encryptionKey). | ||
| DecryptKey | ||
| } else { | ||
| got = NewOptions(defaultExpire, encryptionKey, | ||
| tt.fn()).DecryptKey | ||
| } | ||
| assert.Equal(t, tt.want, got) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestWithMethod(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| fn func() option.Option[Options] | ||
| want jwt.SigningMethod | ||
| }{ | ||
| { | ||
| name: "normal", | ||
| fn: func() option.Option[Options] { | ||
| return nil | ||
| }, | ||
| want: jwt.SigningMethodHS256, | ||
| }, | ||
| { | ||
| name: "set_another_method", | ||
| fn: func() option.Option[Options] { | ||
| return WithMethod(jwt.SigningMethodHS384) | ||
| }, | ||
| want: jwt.SigningMethodHS384, | ||
| }, | ||
| } | ||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| var got jwt.SigningMethod | ||
| if tt.fn() == nil { | ||
| got = NewOptions(defaultExpire, encryptionKey). | ||
| Method | ||
| } else { | ||
| got = NewOptions(defaultExpire, encryptionKey, | ||
| tt.fn()).Method | ||
| } | ||
| assert.Equal(t, tt.want, got) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestWithIssuer(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| fn func() option.Option[Options] | ||
| want string | ||
| }{ | ||
| { | ||
| name: "normal", | ||
| fn: func() option.Option[Options] { | ||
| return nil | ||
| }, | ||
| }, | ||
| { | ||
| name: "set_another_issuer", | ||
| fn: func() option.Option[Options] { | ||
| return WithIssuer("foo") | ||
| }, | ||
| want: "foo", | ||
| }, | ||
| } | ||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| var got string | ||
| if tt.fn() == nil { | ||
| got = NewOptions(defaultExpire, encryptionKey). | ||
| Issuer | ||
| } else { | ||
| got = NewOptions(defaultExpire, encryptionKey, | ||
| tt.fn()).Issuer | ||
| } | ||
| assert.Equal(t, tt.want, got) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestWithGenIDFunc(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| fn func() option.Option[Options] | ||
| want string | ||
| }{ | ||
| { | ||
| name: "normal", | ||
| fn: func() option.Option[Options] { | ||
| return nil | ||
| }, | ||
| }, | ||
| { | ||
| name: "set_another_gen_id_func", | ||
| fn: func() option.Option[Options] { | ||
| return WithGenIDFunc(func() string { | ||
| return "unique id" | ||
| }) | ||
| }, | ||
| want: "unique id", | ||
| }, | ||
| } | ||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| var got string | ||
| if tt.fn() == nil { | ||
| got = NewOptions(defaultExpire, encryptionKey). | ||
| genIDFn() | ||
| } else { | ||
| got = NewOptions(defaultExpire, encryptionKey, | ||
| tt.fn()).genIDFn() | ||
| } | ||
| assert.Equal(t, tt.want, got) | ||
| }) | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.