JWT 鉴权
This commit is contained in:
parent
be9b0007cb
commit
2c597509c7
3 changed files with 64 additions and 39 deletions
|
|
@ -6,19 +6,28 @@ import (
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt"
|
"github.com/golang-jwt/jwt"
|
||||||
"github.com/yaoapp/gou"
|
"github.com/yaoapp/gou"
|
||||||
|
"github.com/yaoapp/gou/session"
|
||||||
|
"github.com/yaoapp/kun/any"
|
||||||
"github.com/yaoapp/kun/exception"
|
"github.com/yaoapp/kun/exception"
|
||||||
"github.com/yaoapp/xiang/config"
|
"github.com/yaoapp/xiang/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// JwtClaims 用户Token
|
// JwtClaims 用户Token
|
||||||
type JwtClaims struct {
|
type JwtClaims struct {
|
||||||
ID int
|
ID int `json:"id"`
|
||||||
Data map[string]interface{}
|
SID string `json:"sid"`
|
||||||
|
Data map[string]interface{} `json:"data"`
|
||||||
jwt.StandardClaims
|
jwt.StandardClaims
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JwtToken JWT令牌
|
||||||
|
type JwtToken struct {
|
||||||
|
Token string `json:"token"`
|
||||||
|
ExpiresAt int64 `json:"expires_at"`
|
||||||
|
}
|
||||||
|
|
||||||
// JwtValidate JWT 校验
|
// 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) {
|
token, err := jwt.ParseWithClaims(tokenString, &JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
return []byte(config.Conf.JWT.Secret), nil
|
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 {
|
if claims, ok := token.Claims.(*JwtClaims); ok && token.Valid {
|
||||||
return claims.Data
|
return claims
|
||||||
}
|
}
|
||||||
|
|
||||||
exception.New("令牌无效", 403).Ctx(token.Claims).Throw()
|
exception.New("令牌无效", 403).Ctx(token.Claims).Throw()
|
||||||
|
|
@ -37,26 +46,42 @@ func JwtValidate(tokenString string) map[string]interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
// JwtMake 生成 JWT
|
// JwtMake 生成 JWT
|
||||||
// subject options[0], audience options[1], issuer options[1]
|
// option: {"subject":"<主题>", "audience": "<接收人>", "issuer":"<签发人>", "timeout": "<有效期,单位秒>", "sid":"<会话ID>"}
|
||||||
func JwtMake(id int, data map[string]interface{}, timeout int64, options ...string) map[string]interface{} {
|
func JwtMake(id int, data map[string]interface{}, option map[string]interface{}) JwtToken {
|
||||||
now := time.Now().Unix()
|
now := time.Now().Unix()
|
||||||
expiresAt := now + timeout
|
sid := ""
|
||||||
|
timeout := int64(3600)
|
||||||
uid := fmt.Sprintf("%d", id)
|
uid := fmt.Sprintf("%d", id)
|
||||||
subject := "User Token"
|
subject := "User Token"
|
||||||
audience := "Xiang Metadata Admin Panel"
|
audience := "Xiang Metadata Admin Panel"
|
||||||
issuer := fmt.Sprintf("xiang:%d", id)
|
issuer := fmt.Sprintf("xiang:%d", id)
|
||||||
length := len(options)
|
if v, has := option["subject"]; has {
|
||||||
if length > 0 {
|
subject = fmt.Sprintf("%v", v)
|
||||||
subject = options[0]
|
|
||||||
}
|
}
|
||||||
if length > 1 {
|
if v, has := option["audience"]; has {
|
||||||
audience = options[1]
|
audience = fmt.Sprintf("%v", v)
|
||||||
}
|
}
|
||||||
if length > 2 {
|
if v, has := option["issuer"]; has {
|
||||||
issuer = options[2]
|
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{
|
claims := &JwtClaims{
|
||||||
ID: id,
|
ID: id,
|
||||||
|
SID: sid, // 会话ID
|
||||||
Data: data,
|
Data: data,
|
||||||
StandardClaims: jwt.StandardClaims{
|
StandardClaims: jwt.StandardClaims{
|
||||||
Id: uid, // 唯一ID
|
Id: uid, // 唯一ID
|
||||||
|
|
@ -73,23 +98,22 @@ func JwtMake(id int, data map[string]interface{}, timeout int64, options ...stri
|
||||||
if err != nil {
|
if err != nil {
|
||||||
exception.New("生成令牌失败", 500).Ctx(err).Throw()
|
exception.New("生成令牌失败", 500).Ctx(err).Throw()
|
||||||
}
|
}
|
||||||
return map[string]interface{}{
|
return JwtToken{
|
||||||
"token": tokenString,
|
Token: tokenString,
|
||||||
"expires_at": expiresAt,
|
ExpiresAt: expiresAt,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessJwtMake xiang.helper.JwtMake 生成JWT
|
// ProcessJwtMake xiang.helper.JwtMake 生成JWT
|
||||||
func ProcessJwtMake(process *gou.Process) interface{} {
|
func ProcessJwtMake(process *gou.Process) interface{} {
|
||||||
process.ValidateArgNums(3)
|
process.ValidateArgNums(2)
|
||||||
id := process.ArgsInt(0)
|
id := process.ArgsInt(0)
|
||||||
data := process.ArgsMap(1)
|
data := process.ArgsMap(1)
|
||||||
timeout := int64(process.ArgsInt(2))
|
option := map[string]interface{}{}
|
||||||
args := []string{}
|
if process.NumOfArgsIs(3) {
|
||||||
for i := 3; i < len(process.Args); i++ {
|
option = process.ArgsMap(2)
|
||||||
args = append(args, fmt.Sprintf("%v", process.Args[i]))
|
|
||||||
}
|
}
|
||||||
return JwtMake(id, data, timeout, args...)
|
return JwtMake(id, data, option)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessJwtValidate xiang.helper.JwtValidate 校验JWT
|
// ProcessJwtValidate xiang.helper.JwtValidate 校验JWT
|
||||||
|
|
|
||||||
|
|
@ -10,24 +10,27 @@ import (
|
||||||
|
|
||||||
func TestJwt(t *testing.T) {
|
func TestJwt(t *testing.T) {
|
||||||
data := map[string]interface{}{"hello": "world", "id": 1}
|
data := map[string]interface{}{"hello": "world", "id": 1}
|
||||||
token := JwtMake(1, data, 1, "Unit Test", "Test", "UnitTest")
|
option := map[string]interface{}{"subject": "Unit Test", "audience": "Test", "issuer": "UnitTest", "timeout": 1, "sid": ""}
|
||||||
tokenString := token["token"].(string)
|
token := JwtMake(1, data, option)
|
||||||
|
tokenString := token.Token
|
||||||
res := JwtValidate(tokenString)
|
res := JwtValidate(tokenString)
|
||||||
assert.Equal(t, float64(1), res["id"])
|
assert.NotNil(t, res)
|
||||||
assert.Equal(t, "world", res["hello"])
|
assert.Equal(t, float64(1), res.Data["id"])
|
||||||
|
assert.Equal(t, "world", res.Data["hello"])
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
assert.Panics(t, func() { JwtValidate(tokenString) })
|
assert.Panics(t, func() { JwtValidate(tokenString) })
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestProcessJwt(t *testing.T) {
|
func TestProcessJwt(t *testing.T) {
|
||||||
data := map[string]interface{}{"hello": "world", "id": 1}
|
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...)
|
process := gou.NewProcess("xiang.helper.JwtMake", args...)
|
||||||
token := process.Run().(map[string]interface{})
|
token := process.Run().(JwtToken)
|
||||||
tokenString := token["token"].(string)
|
tokenString := token.Token
|
||||||
res := gou.NewProcess("xiang.helper.JwtValidate", tokenString).Run().(map[string]interface{})
|
res := gou.NewProcess("xiang.helper.JwtValidate", tokenString).Run().(*JwtClaims)
|
||||||
assert.Equal(t, float64(1), res["id"])
|
assert.Equal(t, float64(1), res.Data["id"])
|
||||||
assert.Equal(t, "world", res["hello"])
|
assert.Equal(t, "world", res.Data["hello"])
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
assert.Panics(t, func() { gou.NewProcess("xiang.helper.JwtValidate", tokenString).Run() })
|
assert.Panics(t, func() { gou.NewProcess("xiang.helper.JwtValidate", tokenString).Run() })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import (
|
||||||
"github.com/dgrijalva/jwt-go"
|
"github.com/dgrijalva/jwt-go"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/yaoapp/xiang/config"
|
"github.com/yaoapp/xiang/config"
|
||||||
"github.com/yaoapp/xiang/user"
|
"github.com/yaoapp/xiang/helper"
|
||||||
"github.com/yaoapp/xiang/xlog"
|
"github.com/yaoapp/xiang/xlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -29,7 +29,7 @@ func bearerJWT(c *gin.Context) {
|
||||||
if config.Conf.Mode == "debug" {
|
if config.Conf.Mode == "debug" {
|
||||||
xlog.Printf("JWT: %s Secret: %s", tokenString, config.Conf.JWT.Secret)
|
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
|
return []byte(config.Conf.JWT.Secret), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -40,10 +40,8 @@ func bearerJWT(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if claims, ok := token.Claims.(*user.JwtClaims); ok && token.Valid {
|
if claims, ok := token.Claims.(*helper.JwtClaims); ok && token.Valid {
|
||||||
c.Set("id", claims.Subject)
|
c.Set("__sid", claims.SID)
|
||||||
c.Set("type", claims.Type)
|
|
||||||
c.Set("name", claims.Name)
|
|
||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue