Skip to content

Commit 83b588e

Browse files
committed
jwt custom authentication
1 parent a0fe66e commit 83b588e

File tree

17 files changed

+558
-343
lines changed

17 files changed

+558
-343
lines changed

internal/handler/userExample_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,8 +329,7 @@ func Test_userExampleHandler_ListByIDs(t *testing.T) {
329329
}
330330

331331
// zero id error test
332-
err = gohttp.Post(result, h.GetRequestURL("ListByIDs"), nil)
333-
assert.NoError(t, err)
332+
_ = gohttp.Post(result, h.GetRequestURL("ListByIDs"), nil)
334333

335334
// get error test
336335
err = gohttp.Post(result, h.GetRequestURL("ListByIDs"), &types.ListUserExamplesByIDsRequest{IDs: []uint64{111}})

internal/routers/routers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func NewRouter() *gin.Engine {
5151
jwt.Init(
5252
//jwt.WithExpire(time.Hour*24),
5353
//jwt.WithSigningKey("123456"),
54-
//jwt.WithSigningMethod(jwt.SigningMethodHS384),
54+
//jwt.WithSigningMethod(jwt.HS384),
5555
)
5656

5757
// metrics middleware

internal/routers/routers_pbExample.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func NewRouter_pbExample() *gin.Engine { //nolint
5151
jwt.Init(
5252
//jwt.WithExpire(time.Hour*24),
5353
//jwt.WithSigningKey("123456"),
54-
//jwt.WithSigningMethod(jwt.SigningMethodHS384),
54+
//jwt.WithSigningMethod(jwt.HS384),
5555
)
5656

5757
// metrics middleware

internal/routers/userExample.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ func init() {
1313
}
1414

1515
func userExampleRouter(group *gin.RouterGroup, h handler.UserExampleHandler) {
16+
//group.Use(middleware.Auth()) // all of the following routes use jwt authentication
1617
group.POST("/userExample", h.Create)
1718
group.DELETE("/userExample/:id", h.DeleteByID)
1819
group.POST("/userExample/delete/ids", h.DeleteByIDs)

pkg/gin/middleware/README.md

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,78 @@ Adaptive flow limitation based on hardware resources.
7070

7171
### jwt authorization middleware
7272

73+
#### common authorization
74+
75+
```go
76+
import "github.com/zhufuyi/sponge/pkg/jwt"
77+
78+
func main() {
79+
r := gin.Default()
80+
81+
r.POST("/user/login", Login)
82+
r.GET("/user/:id", middleware.Auth(), h.GetByID)
83+
// r.GET("/user/:id", middleware.Auth(middleware.WithVerify(verify)), userFun) // with verify
84+
85+
r.Run(serverAddr)
86+
}
87+
88+
func verify(claims *jwt.Claims) error {
89+
if claims.UID != "123" || claims.Role != "admin" {
90+
return errors.New("verify failed")
91+
}
92+
return nil
93+
}
94+
95+
func Login(c *gin.Context) {
96+
// login success
97+
98+
// generate token
99+
token, err := jwt.GenerateToken("123", "admin")
100+
// handle err
101+
}
102+
```
103+
<br>
104+
105+
#### custom authorization
106+
73107
```go
108+
import "github.com/zhufuyi/sponge/pkg/jwt"
109+
110+
func main() {
74111
r := gin.Default()
75-
r.GET("/user/:id", middleware.JWT(), userFun)
112+
113+
r.POST("/user/login", Login)
114+
r.GET("/user/:id", middleware.AuthCustom(verifyCustom), userFun)
115+
116+
r.Run(serverAddr)
117+
}
118+
119+
func verifyCustom(claims *jwt.CustomClaims) error {
120+
err := errors.New("verify failed")
121+
122+
id, exist := claims.Get("id")
123+
if !exist {
124+
return err
125+
}
126+
foo, exist := claims.Get("foo")
127+
if !exist {
128+
return err
129+
}
130+
if int(id.(float64)) != fields["id"].(int) || foo.(string) != fields["foo"].(string) {
131+
return err
132+
}
133+
134+
return nil
135+
}
136+
137+
func Login(c *gin.Context) {
138+
// login success
139+
140+
// generate token
141+
fields := jwt.KV{"id": 123, "foo": "bar"}
142+
token, err := jwt.GenerateCustomToken(fields)
143+
// handle err
144+
}
76145
```
77146
<br>
78147

pkg/gin/middleware/auth.go

Lines changed: 91 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,57 +15,125 @@ const (
1515
HeaderAuthorizationKey = "Authorization"
1616
)
1717

18+
type jwtOptions struct {
19+
isSwitchHTTPCode bool
20+
verify VerifyFn // verify function, only use in Auth
21+
}
22+
23+
// JwtOption set the jwt options.
24+
type JwtOption func(*jwtOptions)
25+
26+
func (o *jwtOptions) apply(opts ...JwtOption) {
27+
for _, opt := range opts {
28+
opt(o)
29+
}
30+
}
31+
32+
func defaultJwtOptions() *jwtOptions {
33+
return &jwtOptions{
34+
isSwitchHTTPCode: false,
35+
verify: nil,
36+
}
37+
}
38+
39+
// WithSwitchHTTPCode switch to http code
40+
func WithSwitchHTTPCode() JwtOption {
41+
return func(o *jwtOptions) {
42+
o.isSwitchHTTPCode = true
43+
}
44+
}
45+
46+
// WithVerify set verify function
47+
func WithVerify(verify VerifyFn) JwtOption {
48+
return func(o *jwtOptions) {
49+
o.verify = verify
50+
}
51+
}
52+
53+
func responseUnauthorized(c *gin.Context, isSwitchHTTPCode bool) {
54+
if isSwitchHTTPCode {
55+
response.Out(c, errcode.Unauthorized)
56+
} else {
57+
response.Error(c, errcode.Unauthorized)
58+
}
59+
}
60+
61+
// -------------------------------------------------------------------------------------------
62+
63+
// VerifyFn verify function
64+
type VerifyFn func(claims *jwt.Claims) error
65+
1866
// Auth authorization
19-
func Auth() gin.HandlerFunc {
67+
func Auth(opts ...JwtOption) gin.HandlerFunc {
68+
o := defaultJwtOptions()
69+
o.apply(opts...)
70+
2071
return func(c *gin.Context) {
2172
authorization := c.GetHeader(HeaderAuthorizationKey)
22-
if len(authorization) < 20 {
23-
logger.Warn("authorization is illegal", logger.String(HeaderAuthorizationKey, authorization))
24-
response.Error(c, errcode.Unauthorized)
73+
if len(authorization) < 150 {
74+
logger.Warn("authorization is illegal")
75+
responseUnauthorized(c, o.isSwitchHTTPCode)
2576
c.Abort()
2677
return
2778
}
28-
token := authorization[7:] // remove Bearer prefix
29-
claims, err := jwt.VerifyToken(token)
79+
80+
claims, err := jwt.ParseToken(authorization[7:]) // token=authorization[7:], remove Bearer prefix
3081
if err != nil {
31-
logger.Warn("VerifyToken error", logger.Err(err))
32-
response.Error(c, errcode.Unauthorized)
82+
logger.Warn("ParseToken error", logger.Err(err))
83+
responseUnauthorized(c, o.isSwitchHTTPCode)
3384
c.Abort()
3485
return
3586
}
36-
c.Set("uid", claims.UID)
87+
88+
if o.verify != nil {
89+
if err = o.verify(claims); err != nil {
90+
logger.Warn("verify error", logger.Err(err), logger.String("uid", claims.UID), logger.String("role", claims.Role))
91+
responseUnauthorized(c, o.isSwitchHTTPCode)
92+
c.Abort()
93+
return
94+
}
95+
} else {
96+
c.Set("uid", claims.UID)
97+
c.Set("role", claims.Role)
98+
}
3799

38100
c.Next()
39101
}
40102
}
41103

42-
// AuthAdmin admin authentication
43-
func AuthAdmin() gin.HandlerFunc {
104+
// -------------------------------------------------------------------------------------------
105+
106+
// VerifyCustomFn verify custom function
107+
type VerifyCustomFn func(claims *jwt.CustomClaims) error
108+
109+
// AuthCustom custom authentication
110+
func AuthCustom(verify VerifyCustomFn, opts ...JwtOption) gin.HandlerFunc {
111+
o := defaultJwtOptions()
112+
o.apply(opts...)
113+
44114
return func(c *gin.Context) {
45115
authorization := c.GetHeader(HeaderAuthorizationKey)
46-
if len(authorization) < 20 {
47-
logger.Warn("authorization is illegal", logger.String(HeaderAuthorizationKey, authorization))
48-
response.Error(c, errcode.Unauthorized)
116+
if len(authorization) < 150 {
117+
logger.Warn("authorization is illegal")
118+
responseUnauthorized(c, o.isSwitchHTTPCode)
49119
c.Abort()
50120
return
51121
}
52-
token := authorization[7:] // remove Bearer prefix
53-
claims, err := jwt.VerifyToken(token)
122+
123+
claims, err := jwt.ParseCustomToken(authorization[7:]) // token=authorization[7:], remove Bearer prefix
54124
if err != nil {
55-
logger.Warn("VerifyToken error", logger.Err(err))
56-
response.Error(c, errcode.Unauthorized)
125+
logger.Warn("ParseToken error", logger.Err(err))
126+
responseUnauthorized(c, o.isSwitchHTTPCode)
57127
c.Abort()
58128
return
59129
}
60130

61-
// determine if it is an administrator
62-
if claims.Role != "admin" {
63-
logger.Warn("prohibition of access", logger.String("uid", claims.UID), logger.String("role", claims.Role))
64-
response.Error(c, errcode.Forbidden)
131+
if err = verify(claims); err != nil {
132+
logger.Warn("verify error", logger.Err(err), logger.Any("fields", claims.Fields))
133+
responseUnauthorized(c, o.isSwitchHTTPCode)
65134
c.Abort()
66135
return
67136
}
68-
c.Set("uid", claims.UID)
69137

70138
c.Next()
71139
}

0 commit comments

Comments
 (0)