仿抖音后端项目中JWT的使用笔记 | 青训营
一、JWT简介
JWT(JSON Web Token)是一种用于在网络应用中进行身份验证和信息传递的开放标准。它由三个部分组成:头部(Header)、载荷(Payload)和签名(Signature)。
- 头部包含了标识令牌类型以及所使用的加密算法。常见的加密算法有HMAC SHA256和RSA。
- 载荷是令牌的主要内容,可以包含一些声明,例如用户的身份信息、权限等。JWT规定了一些标准的声明,如iss(令牌的发行者)、exp(令牌的过期时间)、sub(令牌的主题)等,同时也可以自定义私有声明。
- 签名是为了验证令牌的真实性和完整性而生成的。使用头部和载荷以及一个密钥,通过指定的加密算法生成签名。服务器在接收到JWT后可以使用相同的密钥进行验证,确保令牌未被篡改。
JWT的优势在于它的轻巧、可扩展和无状态性。由于令牌中包含了所有必要的信息,服务器不需要在自身存储会话信息,也无需频繁地查询数据库,因此可以减轻服务器的负担。另外,JWT可以用于跨域通信,并且易于实现和使用。
二、常见登录认证方案
1、基于session的身份认证
浏览器向服务器发送登录请求时,服务器验证通过后,会将用户信息存入session中,服务器会生成一个sessionid放入cookie中,返回给浏览器,浏览器再次发送请求时,会携带cookie,cookie中有sessionid,会一并发送给服务器
2、基于JWT的身份认证
JWT全称JSON Web Token,前台在登录时,将用户信息发送给服务器,服务器将用户信息进行加密,返回JWT给前台,前台将其存到localStorage中,前台在axios中二次封装,拦截请求,后续发送请求时,在Authorization Header中携带上JWT,后台通过提前协商的密钥,解密JWT,验证用户信息,验证成功,响应请求数据,验证失败,返回登录页重新登录。
三、结合GoLang在项目中实现JWT
1、jwt库的引入
开源Gin项目和一些博客都使用的是dgrijalva/jwt-go这个jwt库
go get -u github.com/dgrijalva/jwt-go
2、自定义Claims结构体
需要在Token中保存用户ID信息
type Claims struct {
UserId int64
jwt.StandardClaims
}
3、生成Token
考虑手机端应用的需求,生成标准claim时过期时间为一周。生成Token时调用jwt库的NewWithClaims即可,传入签名算法和claims结构体,签名算法用得最多的是HS256。
func GenerateToken(user dao.UserLogin) (string, error) {
// 设置过期时间为一周
expirationTime := time.Now().Add(24 * 7 * time.Hour)
claims := &Claims{
UserId: user.UserInfoId,
StandardClaims: jwt.StandardClaims{
ExpiresAt: expirationTime.Unix(),
IssuedAt: time.Now().Unix(),
Issuer: "happy_boy_111",
Subject: "L_Q__",
}}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(jwtKey)
if err != nil {
return "", err
}
return tokenString, nil
}
4、校验Token
将前端传来的token字符串传入解析校验函数,校验函数调用ParseWithClaims进行解析,此时有两种解析方法,一种是将解析结果保存到claims变量中,另一种是从ParseWithClaims返回的Token结构体中取出Claims结构体。这里选择第二种,若token字符串合法但过期claims也会有数据,err会提示token过期。
func ParseToken(tokenString string) (*Claims, error) {
// 解析token
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
return jwtKey, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("invalid token")
}
5、设置中间件拦截请求校验Token
当Token校验失败,无论是过期还是不合法直接拒绝用户请求,并将user_id信息保存到应用上下文context中
func JwtAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenStr := c.Query("token")
if tokenStr == "" {
tokenStr = c.PostForm("token")
}
// token不存在
if tokenStr == "" {
c.JSON(http.StatusOK, dao.CommonResponse{StatusCode: 401, StatusMsg: "用户未登录"})
c.Abort()
return
}
// 解析token
token, err := ParseToken(tokenStr)
if err != nil {
c.JSON(http.StatusOK, dao.CommonResponse{StatusCode: 403, StatusMsg: "token不正确"})
c.Abort()
return
}
// token超时检验
if time.Now().Unix() > token.ExpiresAt {
c.JSON(http.StatusOK, dao.CommonResponse{
StatusCode: 404, StatusMsg: "token过期",
})
}
// 将当前请求的userId信息保存到请求的上下文c上
c.Set("user_id", token.UserId)
c.Next() // 后续的处理函数可以用过c.Get("user_id")来获取当前请求的用户信息
}
}
四、笔记总结
在仿抖音后端项目中,我们使用JWT(JSON Web Token)来实现用户身份验证和权限管理。JWT是一种轻量级且安全的身份验证方式,它使得服务器无需存储会话信息,减轻了服务器的负担,并且可以在分布式系统中实现跨域通信。通过合理使用JWT,我们可以构建更安全、可扩展的应用程序。
五、附录
- JWT 官方网站:jwt.io/ 这是JWT的官方网站,提供了JWT的介绍、规范、库和工具等资源,是一个全面且权威的学习来源。
- JSON Web Token (JWT) - Introduction: www.youtube.com/watch?v=7Q1… 这是一段YouTube视频介绍JWT的基本概念和原理,适合初学者入门。
- JSON Web Token (JWT) Authentication Tutorial: www.youtube.com/watch?v=mbs… 这是一段关于JWT身份验证的视频教程,演示了如何使用JWT进行用户身份验证和保护API。
- JSON Web Token (JWT) - Full Course: www.youtube.com/watch?v=7Q1… 这是一门较长的完整课程,涵盖了JWT的各个方面,包括生成和验证令牌、令牌刷新、权限管理等。