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
目录
相关文章
|
19天前
|
JSON JavaScript 数据格式
jwt-auth插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能。
jwt-auth插件实现了基于JWT(JSON Web Tokens)进行认证鉴权的功能。
34 1
|
3月前
|
存储 NoSQL 前端开发
jwt与redis,把生成的token放入redis中进行临时存储
jwt与redis,把生成的token放入redis中进行临时存储
65 0
|
1月前
|
JSON 安全 程序员
[JavaWeb]——JWT令牌技术,如何从获取JWT令牌
[JavaWeb]——JWT令牌技术,如何从获取JWT令牌
|
4天前
|
JSON 前端开发 Java
JWT解密:探秘令牌魔法与Java的完美交互
JWT解密:探秘令牌魔法与Java的完美交互
18 0
JWT解密:探秘令牌魔法与Java的完美交互
|
27天前
|
JSON 前端开发 Java
|
27天前
|
JSON 安全 Java
JWT令牌技术
JSON Web Token (JWT) 是一种安全的、自包含的信息传输格式,常用于身份验证和信息交换。它由Header、Payload和Signature三部分组成,其中Signature用于验证消息完整性和发送者身份。JWT包含用户信息,服务器登录后发送给客户端,客户端使用JWT证明身份访问受保护资源。在Java项目中,可以使用`java-jwt`库进行JWT的生成和解析。要开始使用JWT,需在Maven或Gradle中添加相关依赖,并实现生成和解析JWT的方法。此外,文中还提供了一个简单的Java Web应用示例,展示如何在用户登录和访问受保护资源时使用JWT。
32 0
|
28天前
|
前端开发 Java Spring
SpringBoot通过拦截器和JWT令牌实现登录验证
该文介绍了JWT工具类、匿名访问注解、JWT验证拦截器的实现以及拦截器注册。使用`java-jwt`库生成和验证JWT,JwtUtil类包含generateToken和verifyToken方法。自定义注解`@AllowAnon`允许接口匿名访问。JwtInterceptor在Spring MVC中拦截请求,检查JWT令牌有效性。InterceptorConfig配置拦截器,注册并设定拦截与排除规则。UserController示例展示了注册、登录(允许匿名)和需要验证的用户详情接口。
119 1
|
3月前
JWT令牌的使用
JWT令牌的使用
50 0
|
3月前
|
JSON 算法 前端开发
gin框架JWT验证实践(原理介绍,代码实践)
gin框架JWT验证实践(原理介绍,代码实践)
43 0
|
3月前
|
SQL Java 数据库连接
Spring-Security & JWT 实现 token
Spring-Security & JWT 实现 token
34 0