demo
生成token
type MyClaims struct {
UserName string `json:"username"`
UserId int64 `json:"user_id"`
jwt.StandardClaims
}
const TokenExpireDuration = time.Hour * 2
var MySecret = []byte("ccuiv")
func GenToken(username string, userID int64) (string, error) {
// 创建一个自己的声明
c := MyClaims{
username,
userID, // 自定义字段
jwt.StandardClaims{
ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
Issuer: "skyfall", // 签发人
},
}
// 创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
// 使用指定的secret签名, 并获得完整的,编码后的token
return token.SignedString(MySecret)
}
解析token
// ParseToken 解析JWT
func ParseToken(tokenString string) (*MyClaims, error) {
// 解析token
// 这样直接就是指针,就不用再取地址了
var mc = new(MyClaims)
token, err := jwt.ParseWithClaims(tokenString, mc, func(token *jwt.Token) (i interface{}, err error) {
return MySecret, nil
})
if err != nil {
return nil, err
}
if token.Valid { // 校验token
return mc, nil
}
return nil, errors.New("invalid token")
}
gin中注册中间件
// JWTAuthMiddleware 是认证中间件
func JWTAuthMiddleware() func(c *gin.Context) {
return func(c *gin.Context) {
// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URl里
// 这里假设Token放在Header的Authorization中,并使用Bearer开头,再postman测试接口时选用Bearer Token
// 具体实现方式依据实际情况决定
authHeader := c.Request.Header.Get("Authorization")
if authHeader == "" {
c.JSON(http.StatusOK, gin.H{
"code": 2003,
"msg": "请求头中auth为空",
})
c.Abort()
return
}
// 按空格分割
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
c.JSON(http.StatusOK, gin.H{
"code": 2004,
"msg": "请求头中auth格式错误",
})
c.Abort()
return
}
// parts[1]用来获取到的tokenString,用之前定义好的解析jwt.ParseToken的函数来解析它
mc, err := jwt.ParseToken(parts[1])
if err != nil {
c.JSON(http.StatusOK, gin.H{
"code": 2005,
"msg": "无效的Token",
})
c.Abort()
return
}
// 将当前请求的username信息保存到请求的上下文c上
c.Set("username", mc.Username)
c.Next() // 后续的处理函数可以用过c.Get("username")来获取当前请求的用户信息
}
}
---------------------------*封装后*-----------------------------
---------------------------*封装后*-----------------------------
// JWTAuthMiddleware 基于JWT的认证中间件
func JWTAuthMiddleware() func(c *gin.Context) {
return func(c *gin.Context) {
// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
// 这里假设Token放在Header的Authorization中,并使用Bearer开头
// 具体实现方式依据实际情况决定
authHeader := c.Request.Header.Get("Authorization")
if authHeader == "" {
controlers.ResponseError(c, controlers.CodeNeedLogin)
c.Abort()
return
}
// 按空格分割
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
controlers.ResponseError(c, controlers.CodeInvalidToken)
c.Abort()
return
}
// parts[1]是获取到的token,用之前定义好的解析jwt.ParseToken的函数来解析它
mc, err := jwt.ParseToken(parts[1])
if err != nil {
controlers.ResponseError(c, controlers.CodeInvalidToken)
c.Abort()
return
}
// 将当前请求的userid信息保存到请求的上下文c上
fmt.Println("----:", mc.UserId)
// 放在controller层, 避免循环引用
c.Set(controlers.ContextUserIDKey, mc.UserId)
c.Next() // 后续的处理函数可以用过c.Get("user_id")来获取当前请求的用户信息
}
}
install
go get -u github.com/dgrijalva/jwt-go
使用
定义结构体
规定在jwt里存哪些信息
// 定制需求
type MyClaims struct {
UserName string `json:"username"`
UserId int64 `json:"user_id"`
jwt.StandardClaims
}
定义过期时间
const TokenExpireDuration = time.Hour * 3
定义密钥
var MySecret = []byte("ccuiv")
代码:
type MyClaims struct {
UserName string `json:"username"`
UserId int64 `json:"user_id"`
jwt.StandardClaims
}
const TokenExpireDuration = time.Hour * 2
var MySecret = []byte("ccuiv")
func GenToken(username string, userID int64) (string, error) {
// 创建一个自己的声明
c := MyClaims{
username,
userID, // 自定义字段
jwt.StandardClaims{
ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
Issuer: "skyfall", // 签发人
},
}
// 使用指定的签名方法创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
// 使用指定的secret签名并获得完整的编码后的字符串token
return token.SignedString(MySecret)
}
解析jwt见demo
在gin中注册中间件见demo
gin中调用demo
r.GET("/ping", middlewares.JWTAuthMiddleware(), func(c *gin.Context) {
// 如果是登录的用户, 判断请求头中时候有有效的token
user, _ := controlers.GetCurrentUser(c)
c.JSON(http.StatusOK, user)
})