Go-jwt
简介
jwt 和 token 类似,在服务端加入一个 secret 密钥,又用户发送用户名密码给服务端,服务端验证,验证成功后就生成三个部分 header,payload,signature 组成的 jwt token 给客户端,之后的请求都带上 jwt token,服务端通过 secret 密钥进行验证。
缺点:无法中途废弃
安装
go get -u github.com/dgrijalva/jwt-go
使用步骤
1、生成解析token
import (
"errors"
"github.com/dgrijalva/jwt-go"
"time"
)
// 自定义 secret
var jwtSecret = []byte("testtest")
//Claim是一些实体(通常指的用户)的状态和额外的元数据
type Claims struct {
Username string `json:"username"`
Password string `json:"password"`
jwt.StandardClaims
}
// 根据用户的用户名和密码产生token
func GenerateToken(username, password string) (string, error) {
//设置token有效时间
nowTime := time.Now()
expireTime := nowTime.Add(3 * time.Hour)
claims := Claims{
Username: username,
Password: password,
StandardClaims: jwt.StandardClaims{
// 过期时间
ExpiresAt: expireTime.Unix(),
// 指定token发行人
Issuer: "gin-blog",
},
}
tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
//该方法内部生成签名字符串,再用于获取完整、已签名的token
token, err := tokenClaims.SignedString(jwtSecret)
return token, err
}
// 根据传入的token值获取到Claims对象信息,(进而获取其中的用户名和密码)
func ParseToken(token string) (*Claims, error) {
//用于解析鉴权的声明,方法内部主要是具体的解码和校验的过程,最终返回*Token
tokenClaims, err := jwt.ParseWithClaims(token, &Claims{
}, func(token *jwt.Token) (interface{
}, error) {
return jwtSecret, nil
})
if err != nil {
return nil, err
}
if tokenClaims != nil {
// 从tokenClaims中获取到Claims对象,并使用断言,将该对象转换为我们自己定义的Claims
// 要传入指针,项目中结构体都是用指针传递,节省空间。
if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid {
return claims, nil
}
}
return nil, errors.New("invalid token")
}
2、jwt 中间件
import (
"devops/pkg/jwtOperation"
"github.com/gin-gonic/gin"
"net/http"
"strings"
)
// JWTAuthMiddleware 基于JWT的认证中间件--验证用户是否登录
func JWTAuthMiddleware() func(c *gin.Context) {
return func(c *gin.Context) {
authHeader := c.Request.Header.Get("authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{
"code": 2003,
"msg": "请求头中auth为空",
})
c.Abort()
return
}
// 按空格分割
parts := strings.Split(authHeader, ".")
if len(parts) != 3 {
c.JSON(http.StatusUnauthorized, gin.H{
"code": 2004,
"msg": "请求头中auth格式有误",
})
c.Abort()
return
}
mc, ok := jwtOperation.ParseToken(authHeader)
if ok != nil {
c.JSON(http.StatusUnauthorized, gin.H{
"code": 2005,
"msg": "无效的Token",
})
c.Abort()
return
}
//m := mc.Username
// 将当前请求的username信息保存到请求的上下文c上
c.Set("username", mc.Username)
c.Next() // 后续的处理函数可以用过c.Get("username")来获取当前请求的用户信息
}
}
3、测试登录
func AuthLoginHandler(c *gin.Context) {
// 用户发送用户名和密码过来
var user models.DevopsAuthModel
err := c.ShouldBindJSON(&user)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{
"code": 2001,
"msg": "无效的参数",
})
return
}
tokenString, _ := jwtOperation.GenerateToken(user.UserName, user.Password)
c.JSON(http.StatusOK, gin.H{
"code": 2000,
"msg": "success",
"Token": tokenString,
"username": user.UserName,
})
}
4、路由接入 jwt 中间件
func Routers(e *gin.Engine) {
e.POST("/login", controllers.AuthLoginHandler)
demo1 := e.Group("/demo1")
demo1.Use(middleware.JWTAuthMiddleware())
{
demo1.GET("/get", controllers.GetHandler)
demo1.POST("/post", controllers.GetHandler)
}
}