package client import ( "errors" "fmt" "github.com/dgrijalva/jwt-go" "github.com/gin-gonic/gin" "net/http" "strconv" "strings" "time" "ulink-admin/config" "ulink-admin/frame" "ulink-admin/modules/system/models/model" "ulink-admin/pkg/base" "ulink-admin/pkg/jwt/common" ) // JWTAuth 中间件,检查token func JWTAuth() frame.IMidHandler { return func(c *frame.Context) { //调用过滤去将放行的请求先放行 if DoSquare(c.Context) { return } token := c.Request.Header.Get("Authorization") if token == "" { c.JSON(http.StatusOK, gin.H{ "status": 401, "msg": "请求未携带token,无权限访问", }) c.Abort() return } s := strings.Split(token, " ") if len(s) != 2 { c.JSON(http.StatusOK, gin.H{ "status": 401, "msg": "token格式错误,无权限访问", }) c.Abort() return } j := NewJWT() // parseToken 解析token包含的信息 claims, err := j.ParseToken(s[1]) if err != nil { c.JSON(http.StatusOK, gin.H{ "status": 401, "msg": err.Error(), }) c.Abort() return } appServer := config.GetServerCfg() lock := appServer.Lock if lock == "0" { get, err := base.RedisDB.GET(claims.RedisKey) if err == nil { if !(get == s[1]) { c.JSON(http.StatusOK, gin.H{ "status": 401, "msg": "您的账号已在其他终端登录,请重新登录", }) c.Abort() return } } } if err != nil { c.JSON(http.StatusOK, gin.H{ "status": 401, "msg": err.Error(), }) c.Abort() return } // 继续交由下一个路由处理,并将解析出的信息传递下去 c.Set("claims", claims) } } // JWT 签名结构 type JWT struct { SigningKey []byte } // 一些常量 var ( TokenExpired = errors.New("授权已过期") TokenNotValidYet = errors.New("token not active yet") TokenMalformed = errors.New("令牌非法") TokenInvalid = errors.New("couldn't handle this token") SignKey = "0df9b8db-6f7c-d713-eeab-ecb317696042" userTypes = map[string]string{"00": "SystemUser:", "01": "WechatUser:"} ) // CustomClaims 载荷,可以加一些自己需要的信息 type CustomClaims struct { UserInfo *model.SysMember `json:"userInfo"` jwt.StandardClaims RedisKey string RedisTimeOut int } // NewJWT 新建一个jwt实例 func NewJWT() *JWT { return &JWT{ []byte(GetSignKey()), } } // GetSignKey 获取signKey func GetSignKey() string { return SignKey } // SetSignKey 设置SignKey func SetSignKey(key string) string { SignKey = key return SignKey } // CreateToken 生成一个token func (j *JWT) CreateToken(claims CustomClaims) (string, error) { token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(j.SigningKey) } // CreateUserToken 生成含有用户信息的token func (j *JWT) CreateUserToken(loginType string, u *model.SysMember) (string, error) { jwtConfig := config.GetJwtConfig() strInt64 := strconv.FormatInt(jwtConfig.TimeOut.Nanoseconds()*3600, 10) sec, _ := strconv.Atoi(strInt64) claims := jwt.NewWithClaims(jwt.SigningMethodHS256, CustomClaims{ UserInfo: u, StandardClaims: jwt.StandardClaims{ //设置token小时时效 ExpiresAt: time.Now().Add(jwtConfig.TimeOut * time.Hour).Unix(), IssuedAt: time.Now().Unix(), Issuer: jwtConfig.Issuer, }, RedisKey: fmt.Sprintf("%s|%s|%s", common.LOGIN_MEMBER, loginType, u.UserName), RedisTimeOut: sec, }) return claims.SignedString(j.SigningKey) } // ParseToken 解析Token func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) { token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { return j.SigningKey, nil }) if err != nil { if ve, ok := err.(*jwt.ValidationError); ok { if ve.Errors&jwt.ValidationErrorMalformed != 0 { return nil, TokenMalformed } else if ve.Errors&jwt.ValidationErrorExpired != 0 { // Token is expired return nil, TokenExpired } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { return nil, TokenNotValidYet } else { return nil, TokenInvalid } } } if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { return claims, nil } return nil, TokenInvalid } // RefreshToken 更新token func (j *JWT) RefreshToken(tokenString string) (string, error) { jwt.TimeFunc = func() time.Time { return time.Unix(0, 0) } token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) { return j.SigningKey, nil }) if err != nil { return "", err } if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid { jwt.TimeFunc = time.Now claims.StandardClaims.ExpiresAt = time.Now().Add(24 * time.Hour).Unix() return j.CreateToken(*claims) } return "", TokenInvalid }