JWT是json web token的缩写,它将用户信息加密到token中,然后返回给client,client在下次请求的时候带上token即可。

JWT的构成

Header

JWT的header由两部分组成:

  • 类型
  • 加密算法

Playload

playload可以填充两种类型数据
1.标准中注册的声明:

iss: 签发者 sub: 面向的用户 aud: 接收方 exp: 过期时间 nbf: 生效时间 iat: 签发时间 jti: 唯一身份标识

2.自定义数据

Signature

签名的算法:

  1. HMACSHA256(
  2. base64UrlEncode(header) + "." +
  3. base64UrlEncode(payload),
  4. secret
  5. )

示例代码

生成token
  1. // 加密的key
  2. var jwtKey = []byte("secret_key")
  3. type claims struct {
  4. UserID uint
  5. jwt.StandardClaims
  6. }
  7. // 生成token
  8. func GenerateToken(user model.User)(string,error){
  9. expireTime := time.Now().Add(7*24*time.Hour)
  10. newClaim := claims{
  11. UserID: user.ID,
  12. StandardClaims: jwt.StandardClaims{
  13. ExpiresAt: expireTime.Unix(),
  14. IssuedAt: time.Now().Unix(),
  15. Issuer: "joker",
  16. Subject: "user token",
  17. },
  18. }
  19. token := jwt.NewWithClaims(jwt.SigningMethodHS256,newClaim)
  20. tokenString,err := token.SignedString(jwtKey)
  21. if err != nil {
  22. return "",err
  23. }
  24. return tokenString, nil
  25. }

解析token
  1. // 解析Token
  2. func ParseToken(tokenString string)(*jwt.Token,*claims,error){
  3. newClaim := &claims{}
  4. token, err := jwt.ParseWithClaims(tokenString,newClaim, func(token *jwt.Token) (i interface{}, err error) {
  5. return jwtKey,err
  6. })
  7. return token,newClaim,err
  8. }

注册或者登录的时候发放token
  1. func Register(ctx *gin.Context) {
  2. db := common.GetDB()
  3. // 获取注册数据
  4. name := ctx.PostForm("name")
  5. password := ctx.PostForm("password")
  6. telephone := ctx.PostForm("telephone")
  7. // 校验用户名、密码、手机号码
  8. // 手机号码必须是11位,如果手机号存在则返回已注册
  9. // 密码不能为空
  10. // 用户名如果为空,则生成十位随机字符串作为用户名
  11. if len(telephone) != 11 || len(telephone) == 0 {
  12. response.Response(ctx,http.StatusUnprocessableEntity, 422,nil,"手机号不能为空或者必须是11位")
  13. return
  14. }
  15. if len(password) == 0 {
  16. response.Response(ctx,http.StatusUnprocessableEntity, 422,nil,"密码不能为空")
  17. return
  18. }
  19. if len(name) == 0 {
  20. name = utils.RandomString(10)
  21. fmt.Println(name)
  22. }
  23. // 数据库中查找手机号是否存在,如果存在,则返回已注册
  24. if isTelephoneExist(db, telephone) {
  25. response.Response(ctx,http.StatusUnprocessableEntity, 422,nil,"手机号码已被注册")
  26. return
  27. }
  28. // 密码加密
  29. hasePassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
  30. if err != nil {
  31. response.Response(ctx,http.StatusInternalServerError, 500,nil,"密码加密失败")
  32. return
  33. }
  34. // 开始注册
  35. newUser := model.User{
  36. UserName: name,
  37. PassWord: string(hasePassword),
  38. Telephone: telephone,
  39. }
  40. db.Create(&newUser)
  41. // 生成token
  42. token, err := common.GenerateToken(newUser)
  43. if err != nil {
  44. ctx.JSON(500, gin.H{
  45. "code": 500,
  46. "msg": "系统错误",
  47. })
  48. response.Response(ctx,http.StatusInternalServerError, 500,nil,"系统错误")
  49. log.Println("generate token failed. err : " + err.Error())
  50. return
  51. }
  52. // 注册成功
  53. response.Success(ctx,gin.H{"token":token,},"注册成功")
  54. }

定义中间件来进行认证
  1. // 用户认证的中间件
  2. func AuthMiddleware() gin.HandlerFunc {
  3. return func(ctx *gin.Context) {
  4. // 从请求中获取Authorization
  5. tokenString := ctx.GetHeader("Authorization")
  6. fmt.Println(tokenString)
  7. // 判断Authorization是否合法
  8. if tokenString == "" || !strings.HasPrefix(tokenString, "Bearer"){
  9. ctx.JSON(http.StatusUnauthorized,gin.H{
  10. "code":401,
  11. "msg": "权限不足",
  12. })
  13. ctx.Abort()
  14. return
  15. }
  16. log.Println("Authorization 合法")
  17. // 解析Authorization
  18. tokenString = tokenString[7:]
  19. token, claims, err := common.ParseToken(tokenString)
  20. if err != nil || !token.Valid {
  21. ctx.JSON(http.StatusUnauthorized,gin.H{
  22. "code":401,
  23. "msg": "权限不足",
  24. })
  25. ctx.Abort()
  26. return
  27. }
  28. log.Println("token 解析成功")
  29. // 获取user信息
  30. userId := claims.UserID
  31. db := common.GetDB()
  32. var user model.User
  33. db.First(&user,userId)
  34. // 用户不存在,返回401
  35. if user.ID == 0{
  36. ctx.JSON(http.StatusUnauthorized,gin.H{
  37. "code":401,
  38. "msg": "权限不足",
  39. })
  40. ctx.Abort()
  41. return
  42. }
  43. // 用户存在,写入上下文
  44. ctx.Set("user",user)
  45. ctx.Next()
  46. }
  47. }