开发者社区> newtrek> 正文

gin 基于JWT实现token令牌功能

简介: token 我的理解是一种凭证,客户端请求时携带此凭证才能有效访问需要验证凭证的服务端接口,而且token可以加密携带客户端的一些信息,比如基本的信息是有效期,生效日期,可以看作是令牌。
+关注继续查看

token 我的理解是一种凭证,客户端请求时携带此凭证才能有效访问需要验证凭证的服务端接口,而且token可以加密携带客户端的一些信息,比如基本的信息是有效期,生效日期,可以看作是令牌。加密后是一串字符串

基于JWT的Token认证机制实现

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。

JWT的组成

一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。

例子

jwt.go 负责token生成,验证

package jwt

import (
    "github.com/gin-gonic/gin"
    "github.com/dgrijalva/jwt-go"
    "errors"
    "time"
    "net/http"
    "log"
)
// 中间件,检查token
func JWTAuth() gin.HandlerFunc {
    return func(c *gin.Context) {
        token :=  c.Request.Header.Get("token")
        if token == ""{
            c.JSON(http.StatusOK,gin.H{
                "status":-1,
                "msg":"请求未携带token,无权限访问",
            })
            c.Set("isPass", false)
            return
        }

        log.Print("get token: ",token)

        j := NewJWT()
        // parseToken
        claims, err := j.ParseToken(token)
        if err != nil {
            if err == TokenExpired {
                c.JSON(http.StatusOK,gin.H{
                    "status":-1,
                    "msg":"授权已过期",
                })
                c.Set("isPass", false)
                return
            }
            c.JSON(http.StatusOK, gin.H{
                "status": -1,
                "msg": err.Error(),
                })
            c.Set("isPass", false)
            return
        }
        c.Set("isPass", true)
        c.Set("claims",claims)
    }
}
// 签名
type JWT struct {
    SigningKey []byte
}

var (
    TokenExpired error = errors.New("Token is expired")
    TokenNotValidYet error = errors.New("Token not active yet")
    TokenMalformed error = errors.New("That's not even a token")
    TokenInvalid error = errors.New("Couldn't handle this token:")
    SignKey string = "newtrekWang"
)
// 载荷
type CustomClaims struct {
    ID string `json:"userId"`
    Name string `json:"name"`
    Phone string `json:"phone"`
    jwt.StandardClaims
}
func NewJWT() *JWT {
    return &JWT{
        []byte(GetSignKey()),
    }
}
func GetSignKey() string {
    return SignKey
}
func SetSignKey(key string) string {
    SignKey = key
    return SignKey
}


func (j *JWT) CreateToken(claims CustomClaims) (string, error) {
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString(j.SigningKey)
}

func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) {
    token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
        return j.SigningKey, nil
    })
    if err != nil {
        if ve, ok := err.(*jwt.ValidationError); ok {
            if ve.Errors&jwt.ValidationErrorMalformed != 0 {
                return nil, TokenMalformed
            } else if ve.Errors&jwt.ValidationErrorExpired != 0 {
                // Token is expired
                return nil, TokenExpired
            } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
                return nil, TokenNotValidYet
            } else {
                return nil, TokenInvalid
            }
        }
    }
    if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
        return claims, nil
    }
    return nil, TokenInvalid
}

func (j *JWT) RefreshToken(tokenString string) (string, error) {
    jwt.TimeFunc = func() time.Time {
        return time.Unix(0, 0)
    }
    token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
        return j.SigningKey, nil
    })
    if err != nil {
        return "", err
    }
    if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
        jwt.TimeFunc = time.Now
        claims.StandardClaims.ExpiresAt = time.Now().Add(1 * time.Hour).Unix()
        return j.CreateToken(*claims)
    }
    return "", TokenInvalid
}

api.go 路由处理

package api

import (
    "github.com/gin-gonic/gin"
    "net/http"
    myjwt "ColdChainServer/middleware/jwt"
    jwtgo "github.com/dgrijalva/jwt-go"
    "time"
    "log"
    "ColdChainServer/module"
)

func Test(c *gin.Context){
    c.JSON(http.StatusOK,gin.H{
        "message":"hello",
    })
}

func GetDataByTime(c *gin.Context) {
    isPass := c.GetBool("isPass")
    if !isPass {
        return
    }
    claims := c.MustGet("claims").(*myjwt.CustomClaims)
    if claims != nil {
        c.JSON(http.StatusOK, gin.H{
            "status": 0,
            "msg":    "token有效",
            "data":   claims,
        })
    }
}

type LoginResult struct{
    Token string `json:"token"`
    module.User
}
// 登录
func Login(c *gin.Context) {
    var loginReq module.LoginReq
    if c.BindJSON(&loginReq) == nil{
        isPass,user,err := module.LoginCheck(loginReq)
        if isPass {
            generateToken(c,user)
        }else {
            c.JSON(http.StatusOK,gin.H{
                "status":-1,
                "msg":"验证失败"+err.Error(),
            })
            return
        }
    }else{
        c.JSON(http.StatusOK,gin.H{
            "status":-1,
            "msg":"json 解析失败",
        })
        return
    }


}
// 生成令牌
func generateToken(c *gin.Context, user module.User) {
    j := &myjwt.JWT{
        []byte("newtrekWang"),
    }

    claims := myjwt.CustomClaims{
        user.Id,
        user.Name,
        user.Phone,
        jwtgo.StandardClaims{
            NotBefore: int64(time.Now().Unix() - 1000),// 签名生效时间
            ExpiresAt: int64(time.Now().Unix() + 3600),// 过期时间 一小时
            Issuer: "newtrekWang",//签名的发行者
        },
    }

    token, err := j.CreateToken(claims)

    if err != nil {
        c.JSON(http.StatusOK,gin.H{
            "status":-1,
            "msg":err.Error(),
        })
        return
    }

    log.Println(token)

    data := LoginResult{
        User:user,
        Token:token,
    }
    c.JSON(http.StatusOK,gin.H{
        "status":0,
        "msg":"登录成功!",
        "data":data,
    })
    return
}

main.go 路由分发

package main

import (
    "github.com/gin-gonic/gin"

    "ColdChainServer/api"
    "ColdChainServer/middleware/jwt"
)

func main() {
    r := gin.Default()
    r.GET("/",api.Test)
    r.POST("/login",api.Login)
    r.POST("/register",api.Register)
    r.POST("/editUser",api.UpdateUser)

    taR := r.Group("/data")
    taR.Use(jwt.JWTAuth())

    {
        taR.GET("/dataByTime",api.GetDataByTime)
    }
    r.Run(":8080")
}

验证功能

登录

登录

登录成功结果

请求需要token的接口

携带token


携带token请求结果

未携带token


image.png

无效token
image.png

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
令牌认证机制(token),相关各类JWT库(java)
令牌认证机制(token),相关各类JWT库(java)
99 0
JWT、 超详细、分析、token、鉴权、组成、优势 上
JWT、 超详细、分析、token、鉴权、组成、优势 上
127 0
用户鉴权、JWT(JSON Web Token)是什么?
用户鉴权、JWT(JSON Web Token)是什么?
72 0
JWT如何解析过期的token中的信息
JWT如何解析过期的token中的信息
442 0
PHP使用jwt生成token,做api的用户认证firebase/php-jwt
PHP使用jwt生成token,做api的用户认证firebase/php-jwt
197 0
PHP实现JWT lcobucci/jwt生成jwt token
PHP实现JWT lcobucci/jwt生成jwt token
215 0
一文带你了解CSRF、Cookie、Session和token,JWT之间的关系
1.Cookie和Session兄弟 由于HTTP协议本身是无状态的,也就是说同一个用户前一次HTTP请求和后一次HTTP请求时相互独立的,无法判断后一次请求的用户是不是刚才的用户。为了记录用户的状态,才有了Cookie。Cookie实际上以key-value键值对的形式存储了一些文本信息数据,它将数据保存在客户端(浏览器)。
140 0
【SpringBoot】46、SpringBoot中整合JWT实现Token验证(拦截器篇)
上篇文章我们已经实现了使用自定义注解验证 token 信息,这样我们就会发现,当我们需要验证的接口较多时,我们需要每个方法上面都加上 @JwtToken 这个注解,也是非常麻烦, 本片文章,我们继续使用拦截器来实现 token 信息的验证
222 0
【SpringBoot】45、SpringBoot中整合JWT实现Token验证(注解篇)
上篇文章,我们已经在 SpringBoot 中整合了 JWT 并实现了 Token 验证,那我们在实际应用中就会发现,如果每个 视图层(controller)都手动验证 token,代码就会显得特别臃肿,本篇文章主要为了解决该问题。
61 0
【SpringBoot】44、SpringBoot中整合JWT实现Token验证(整合篇)
Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于 JSON 的开放标准((RFC 7519),该 token 被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。
122 0
+关注
newtrek
王家兴,男,90后草根站长,技术宅,有时间就晚上出去跑跑步 目前的博客,除了一些笔记,其它全部原创输出,就当自己瞎写吧,反正前期也没指望有人看。 爱逛技术社区,看书,王者荣耀,美剧《硅谷》 主要擅长Android应用开发,但目前还没达到高级工程师级别,正在向这个目标努力。
文章
问答
视频
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载