详解Go-JWT-RESTful身份认证教程

2020-01-28 14:15:38于丽

4.1.2 生成JWT-string(核心代码)

1.自定义payload结构体,不建议直接使用 dgrijalva/jwt-go jwt.StandardClaims结构体.因为他的payload包含的用户信息太少.

2.实现 type Claims interfaceValid() error 方法,自定义校验内容

3.生成JWT-string jwtGenerateToken(m *User,d time.Duration) (string, error)

https://github.com/libragen/felix/blob/master/model/m_jwt.go


package model

import (
  "errors"
  "fmt"
  "time"

  "github.com/dgrijalva/jwt-go"
  "github.com/sirupsen/logrus"
)

var AppSecret = ""//viper.GetString会设置这个值(32byte长度)
var AppIss = "github.com/libragen/felix"//这个值会被viper.GetString重写

//自定义payload结构体,不建议直接使用 dgrijalva/jwt-go `jwt.StandardClaims`结构体.因为他的payload包含的用户信息太少.
type userStdClaims struct {
  jwt.StandardClaims
  *User
}
//实现 `type Claims interface` 的 `Valid() error` 方法,自定义校验内容
func (c userStdClaims) Valid() (err error) {
  if c.VerifyExpiresAt(time.Now().Unix(), true) == false {
    return errors.New("token is expired")
  }
  if !c.VerifyIssuer(AppIss, true) {
    return errors.New("token's issuer is wrong")
  }
  if c.User.Id < 1 {
    return errors.New("invalid user in jwt")
  }
  return
}

func jwtGenerateToken(m *User,d time.Duration) (string, error) {
  m.Password = ""
  expireTime := time.Now().Add(d)
  stdClaims := jwt.StandardClaims{
    ExpiresAt: expireTime.Unix(),
    IssuedAt: time.Now().Unix(),
    Id:    fmt.Sprintf("%d", m.Id),
    Issuer:  AppIss,
  }

  uClaims := userStdClaims{
    StandardClaims: stdClaims,
    User:      m,
  }

  token := jwt.NewWithClaims(jwt.SigningMethodHS256, uClaims)
  // Sign and get the complete encoded token as a string using the secret
  tokenString, err := token.SignedString([]byte(AppSecret))
  if err != nil {
    logrus.WithError(err).Fatal("config is wrong, can not generate jwt")
  }
  return tokenString, err
}


//JwtParseUser 解析payload的内容,得到用户信息
//gin-middleware 会使用这个方法
func JwtParseUser(tokenString string) (*User, error) {
  if tokenString == "" {
    return nil, errors.New("no token is found in Authorization Bearer")
  }
  claims := userStdClaims{}
  _, err := jwt.ParseWithClaims(tokenString, &claims, func(token *jwt.Token) (interface{}, error) {
    if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
      return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
    }
    return []byte(AppSecret), nil
  })
  if err != nil {
    return nil, err
  }
  return claims.User, err
}

4.2 JWT中间件(middleware)

1.从url-query的_t获取JWT-string或者从请求头 Authorization中获取JWT-string

2.model.JwtParseUser(token)解析JWT-string获取User结构体(减少中间件查询数据库的操作和时间)

3.设置用户信息到gin.Context 其他的handler通过gin.Context.Get(contextKeyUserObj),在进行用户Type Assert得到model.User 结构体.