zoukankan      html  css  js  c++  java
  • gin框架教程三:JWT的使用

    gin框架教程代码地址:
    https://github.com/jiujuan/gin-tutorial

    JWT介绍

    JWT (JSON Web Token) 是一种规范。这个规范允许我们使用JWT在用户和服务器之间安全传递信息.

    JWT的组成:

    jwt分3个部分,Header 头部、Payload 载荷、Signature 签名, 用 dot(.) 点分开
    一般像下面这个样子:
    xxxx.yyyy.zzzz

    一般表示算法和类型

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    

    JSON一般都会经过Base64Url编码

    Payload:

    payload包含claims, claims一般包含实体信息(user信息等)和额外的信息。其中claims又分3种类型:
    Registered claims: 这个推荐设置的选项,但不是强制的。 它提供了一些有用的信息,iss (issuer), exp (expiration time), sub (subject), aud(audience), and others
    Public claims:在使用JWTs时可以被定义。
    Private claims:用户自定义的一些信息

    example playload:

    {
      "sub": "1234567890",
      "name": "John Doe",
      "admin": true
    }
    

    也会经过base64编码

    Signature:

    创建一个签名,我们要使用到header,payload 和 secret,在用算法计算他们
    比如用 hmac sha256 算法:

    HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret)
    

    计算出来长这个样子:
    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NjY1OTI3MjYsImlhdCI6MTU2NjU1NjcyNiwidXNlcl9pZCI6MSwicGFzc3dvcmQiOiIxMTEiLCJ1c2VybmFtZSI6InRvbSIsImZ1bGxfbmFtZSI6InRvbSIsInBlcm1pc3Npb25zIjpbXX0.HpkWP4CqlZBt-Ys_QYNs4yPd1GaR4oGxOeJU4In9co8

    更多更详细介绍请参阅:https://jwt.io/introduction/

    Go example

    使用的go jwt库: https://github.com/dgrijalva/jwt-go,这个库有6k多的start,确实是很受欢迎,所以用这个库来写demo

    demo例子:

    package main
    
    import (
        "errors"
        "fmt"
        jwt "github.com/dgrijalva/jwt-go"
        "github.com/gin-gonic/gin"
        "net/http"
        "time"
    )
    
    const (
        ErrorServerBusy = "server is busy"
        ErrorReLogin = "relogin"
    )
    
    type JWTClaims struct {
        jwt.StandardClaims
        UserID int `json:"user_id"`
        Password string `json:"password"`
        Username string `json:"username"`
    }
    
    var (
        Secret = "123#111"  //salt
        ExpireTime = 3600  //token expire time
    )
    
    func main() {
        r := gin.Default()
        r.GET("/login/:username/:password", login)
        r.GET("/verify/:token", verify)
        r.GET("/refresh/:token", refresh)
        r.GET("/sayHello/:token", sayHello)
        _ = r.Run(":8000")
    }
    
    //generate jwt token
    func genToken(claims *JWTClaims) (string, error) {
        token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
        signedToken, err := token.SignedString([]byte(Secret))
        if err != nil {
            return "", errors.New(ErrorServerBusy)
        }
        return signedToken, nil
    }
    
    //登录,获取jwt token
    func login(c *gin.Context) {
        username := c.Param("username")
        password := c.Param("password")
        claims := &JWTClaims{
            UserID: 1,
            Username: username,
            Password: password,
        }
        claims.IssuedAt = time.Now().Unix()
        claims.ExpiresAt = time.Now().Add(time.Second * time.Duration(ExpireTime)).Unix()
        singedToken, err := genToken(claims)
        if err != nil {
            c.String(http.StatusNotFound, err.Error())
            return
        }
        c.String(http.StatusOK, singedToken)
    }
    
    //验证jwt token
    func verifyAction(strToken string) (*JWTClaims, error) {
        token, err := jwt.ParseWithClaims(strToken, &JWTClaims{}, func(token *jwt.Token) (interface{}, error) {
            return []byte(Secret), nil
        })
        if err != nil {
            return nil, errors.New(ErrorServerBusy)
        }
    
        claims, ok := token.Claims.(*JWTClaims)
        if !ok {
            return nil, errors.New(ErrorReLogin)
        }
        if err := token.Claims.Valid(); err != nil {
            return nil, errors.New(ErrorReLogin)
        }
    
        fmt.Println("verify")
        return claims, nil
    }
    
    func sayHello(c *gin.Context) {
        strToken := c.Param("token")
        claim, err := verifyAction(strToken)
        if err != nil {
            c.String(http.StatusNotFound, err.Error())
        }
        c.String(http.StatusOK, "hello, ", claim.Username)
    }
    
    func verify(c *gin.Context) {
        strToken := c.Param("token")
        claim, err := verifyAction(strToken)
        if err != nil {
            c.String(http.StatusNotFound, err.Error())
            return
        }
        c.String(http.StatusOK, "verify: ", claim.Username)
    }
    
    func refresh(c *gin.Context) {
        strToken := c.Param("token")
        claims, err := verifyAction(strToken)
        if err != nil {
            c.String(http.StatusNotFound, err.Error())
            return
        }
        claims.ExpiresAt = time.Now().Unix() + (claims.ExpiresAt - claims.IssuedAt)
        signedToken, err := genToken(claims)
        if err != nil {
            c.String(http.StatusNotFound, err.Error())
            return
        }
        c.String(http.StatusOK, signedToken, ", ", claims.ExpiresAt)
    }
    
    
    

    JWT资源

    对于jwt的了解: https://jwt.io
    jwt介绍:https://jwt.io/introduction/
    rfc: https://tools.ietf.org/html/rfc7519
    jwt方法参数定义的介绍:https://www.iana.org/assignments/jwt/jwt.xhtml
    jwt handbook: https://auth0.com/resources/ebooks/jwt-handbook

    JWT各种库:https://jwt.io/#libraries

  • 相关阅读:
    经典卷积神经网络算法(4):GoogLeNet
    经典卷积神经网络算法(3):VGG
    经典卷积神经网络算法(2):AlexNet
    经典卷积神经网络算法(1):LeNet-5
    卷积神经网络入门篇
    人工神经网络实践
    Python操作Oracle数据库:cx_Oracle
    源码剖析@ApiImplicitParam对@RequestParam的required属性的侵入性
    实战SpringCloud通用请求字段拦截处理
    Elasticsearch系列---生产集群部署(下)
  • 原文地址:https://www.cnblogs.com/jiujuan/p/11403066.html
Copyright © 2011-2022 走看看