From 2c597509c73550fd45a237003623ac75fd2d8a1a Mon Sep 17 00:00:00 2001 From: Max Date: Mon, 22 Nov 2021 00:42:53 +0800 Subject: [PATCH] =?UTF-8?q?JWT=20=E9=89=B4=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- helper/jwt.go | 70 +++++++++++++++++++++++++++++++--------------- helper/jwt_test.go | 23 ++++++++------- service/guard.go | 10 +++---- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/helper/jwt.go b/helper/jwt.go index 785f6a7c..227dbf85 100644 --- a/helper/jwt.go +++ b/helper/jwt.go @@ -6,19 +6,28 @@ import ( "github.com/golang-jwt/jwt" "github.com/yaoapp/gou" + "github.com/yaoapp/gou/session" + "github.com/yaoapp/kun/any" "github.com/yaoapp/kun/exception" "github.com/yaoapp/xiang/config" ) // JwtClaims 用户Token type JwtClaims struct { - ID int - Data map[string]interface{} + ID int `json:"id"` + SID string `json:"sid"` + Data map[string]interface{} `json:"data"` jwt.StandardClaims } +// JwtToken JWT令牌 +type JwtToken struct { + Token string `json:"token"` + ExpiresAt int64 `json:"expires_at"` +} + // JwtValidate JWT 校验 -func JwtValidate(tokenString string) map[string]interface{} { +func JwtValidate(tokenString string) *JwtClaims { token, err := jwt.ParseWithClaims(tokenString, &JwtClaims{}, func(token *jwt.Token) (interface{}, error) { return []byte(config.Conf.JWT.Secret), nil }) @@ -29,7 +38,7 @@ func JwtValidate(tokenString string) map[string]interface{} { } if claims, ok := token.Claims.(*JwtClaims); ok && token.Valid { - return claims.Data + return claims } exception.New("令牌无效", 403).Ctx(token.Claims).Throw() @@ -37,26 +46,42 @@ func JwtValidate(tokenString string) map[string]interface{} { } // JwtMake 生成 JWT -// subject options[0], audience options[1], issuer options[1] -func JwtMake(id int, data map[string]interface{}, timeout int64, options ...string) map[string]interface{} { +// option: {"subject":"<主题>", "audience": "<接收人>", "issuer":"<签发人>", "timeout": "<有效期,单位秒>", "sid":"<会话ID>"} +func JwtMake(id int, data map[string]interface{}, option map[string]interface{}) JwtToken { now := time.Now().Unix() - expiresAt := now + timeout + sid := "" + timeout := int64(3600) uid := fmt.Sprintf("%d", id) subject := "User Token" audience := "Xiang Metadata Admin Panel" issuer := fmt.Sprintf("xiang:%d", id) - length := len(options) - if length > 0 { - subject = options[0] + if v, has := option["subject"]; has { + subject = fmt.Sprintf("%v", v) } - if length > 1 { - audience = options[1] + if v, has := option["audience"]; has { + audience = fmt.Sprintf("%v", v) } - if length > 2 { - issuer = options[2] + if v, has := option["issuer"]; has { + issuer = fmt.Sprintf("%v", v) } + if v, has := option["sid"]; has { + sid = fmt.Sprintf("%v", v) + } + if v, has := option["timeout"]; has { + timeout = int64(any.Of(v).CInt()) + } + + expiresAt := now + timeout + if sid == "" { + sid = session.ID() + } + + // 设定会话过期时间 (并写需要加锁,这个逻辑需要优化) + // session.Global().Expire(time.Duration(timeout) * time.Second) + claims := &JwtClaims{ ID: id, + SID: sid, // 会话ID Data: data, StandardClaims: jwt.StandardClaims{ Id: uid, // 唯一ID @@ -73,23 +98,22 @@ func JwtMake(id int, data map[string]interface{}, timeout int64, options ...stri if err != nil { exception.New("生成令牌失败", 500).Ctx(err).Throw() } - return map[string]interface{}{ - "token": tokenString, - "expires_at": expiresAt, + return JwtToken{ + Token: tokenString, + ExpiresAt: expiresAt, } } // ProcessJwtMake xiang.helper.JwtMake 生成JWT func ProcessJwtMake(process *gou.Process) interface{} { - process.ValidateArgNums(3) + process.ValidateArgNums(2) id := process.ArgsInt(0) data := process.ArgsMap(1) - timeout := int64(process.ArgsInt(2)) - args := []string{} - for i := 3; i < len(process.Args); i++ { - args = append(args, fmt.Sprintf("%v", process.Args[i])) + option := map[string]interface{}{} + if process.NumOfArgsIs(3) { + option = process.ArgsMap(2) } - return JwtMake(id, data, timeout, args...) + return JwtMake(id, data, option) } // ProcessJwtValidate xiang.helper.JwtValidate 校验JWT diff --git a/helper/jwt_test.go b/helper/jwt_test.go index ae29d502..59707b27 100644 --- a/helper/jwt_test.go +++ b/helper/jwt_test.go @@ -10,24 +10,27 @@ import ( func TestJwt(t *testing.T) { data := map[string]interface{}{"hello": "world", "id": 1} - token := JwtMake(1, data, 1, "Unit Test", "Test", "UnitTest") - tokenString := token["token"].(string) + option := map[string]interface{}{"subject": "Unit Test", "audience": "Test", "issuer": "UnitTest", "timeout": 1, "sid": ""} + token := JwtMake(1, data, option) + tokenString := token.Token res := JwtValidate(tokenString) - assert.Equal(t, float64(1), res["id"]) - assert.Equal(t, "world", res["hello"]) + assert.NotNil(t, res) + assert.Equal(t, float64(1), res.Data["id"]) + assert.Equal(t, "world", res.Data["hello"]) time.Sleep(2 * time.Second) assert.Panics(t, func() { JwtValidate(tokenString) }) } func TestProcessJwt(t *testing.T) { data := map[string]interface{}{"hello": "world", "id": 1} - args := []interface{}{1, data, 1, "Unit Test", "Test", "UnitTest"} + option := map[string]interface{}{"subject": "Unit Test", "audience": "Test", "issuer": "UnitTest", "timeout": 1, "sid": ""} + args := []interface{}{1, data, option} process := gou.NewProcess("xiang.helper.JwtMake", args...) - token := process.Run().(map[string]interface{}) - tokenString := token["token"].(string) - res := gou.NewProcess("xiang.helper.JwtValidate", tokenString).Run().(map[string]interface{}) - assert.Equal(t, float64(1), res["id"]) - assert.Equal(t, "world", res["hello"]) + token := process.Run().(JwtToken) + tokenString := token.Token + res := gou.NewProcess("xiang.helper.JwtValidate", tokenString).Run().(*JwtClaims) + assert.Equal(t, float64(1), res.Data["id"]) + assert.Equal(t, "world", res.Data["hello"]) time.Sleep(2 * time.Second) assert.Panics(t, func() { gou.NewProcess("xiang.helper.JwtValidate", tokenString).Run() }) } diff --git a/service/guard.go b/service/guard.go index b9dad96d..a94a5869 100644 --- a/service/guard.go +++ b/service/guard.go @@ -7,7 +7,7 @@ import ( "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" "github.com/yaoapp/xiang/config" - "github.com/yaoapp/xiang/user" + "github.com/yaoapp/xiang/helper" "github.com/yaoapp/xiang/xlog" ) @@ -29,7 +29,7 @@ func bearerJWT(c *gin.Context) { if config.Conf.Mode == "debug" { xlog.Printf("JWT: %s Secret: %s", tokenString, config.Conf.JWT.Secret) } - token, err := jwt.ParseWithClaims(tokenString, &user.JwtClaims{}, func(token *jwt.Token) (interface{}, error) { + token, err := jwt.ParseWithClaims(tokenString, &helper.JwtClaims{}, func(token *jwt.Token) (interface{}, error) { return []byte(config.Conf.JWT.Secret), nil }) @@ -40,10 +40,8 @@ func bearerJWT(c *gin.Context) { return } - if claims, ok := token.Claims.(*user.JwtClaims); ok && token.Valid { - c.Set("id", claims.Subject) - c.Set("type", claims.Type) - c.Set("name", claims.Name) + if claims, ok := token.Claims.(*helper.JwtClaims); ok && token.Valid { + c.Set("__sid", claims.SID) c.Next() return }