JWT (JSON Web Token) 是一种规范。这个规范允许我们使用JWT在用户和服务器之间安全传递信息.jwt分3个部分,Header 头部、Payload 载荷、Signature 签名, 用 dot(.) 点分开。想要具体理解jwt的童鞋可以自行百度,这里就不再赘述。
首先我们需要引入jwt库
github.com/dgrijalva/jwt-go
package main
import ( "errors" "github.com/dgrijalva/jwt-go" "github.com/gin-contrib/cors" "github.com/gin-gonic/gin" "net/http" "time")
const ( ErrorServerBusy = "server is busy" ErrorReLogin = "relogin")
type User struct { Id int Name string}type JWTClaims struct { jwt.StandardClaims User User}
var ( Secret = "123#111" //salt ExpireTime = 3600 //token expire time)
//生成 jwt tokenfunc genToken(user User) (string, error) { claims := &JWTClaims{ User: user, } claims.IssuedAt = time.Now().Unix() claims.ExpiresAt = time.Now().Add(time.Second * time.Duration(ExpireTime)).Unix() token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) signedToken, err := token.SignedString([]byte(Secret)) if err != nil { return "", errors.New(ErrorServerBusy) } return signedToken, nil}
//验证jwt tokenfunc verifyToken(ctx *gin.Context) (*JWTClaims, error) { strToken := ctx.Request.Header.Get("token") 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) } return claims, nil}// 更新tokenfunc refresh(c *gin.Context) (string, error) { claims, _ := verifyToken(c) return genToken(claims.User)}
func jwtAuth(ctx *gin.Context) { if _, err := verifyToken(ctx); err == nil { ctx.Next() } else { ctx.JSON(http.StatusOK, gin.H{"code": 4001}) ctx.Abort() }}
func main() { router := gin.Default() //在web开发中,浏览器处于安全考虑会限制跨域请求。 //我们采用前后端分离的方式写接口的时候服务器端要允许跨域请求 //使用 cors中间件 允许跨域 router.Use(cors.Default()) router.GET("/login", func(ctx *gin.Context) { user := User{1, "hanyun"} singedToken, err := genToken(user) if err == nil { ctx.JSON(http.StatusOK, gin.H{"code": 0, "token": singedToken}) } else { ctx.JSON(http.StatusOK, gin.H{"code": 1, "token": singedToken}) } }) //使用自定义的jwtAuth中间件 router.Use(jwtAuth) router.GET("/user", func(context *gin.Context) { claims, _ := verifyToken(context) context.JSON(http.StatusOK, gin.H{"code": 0, "user": claims.User}) }) router.GET("/refresh", func(context *gin.Context) { singedToken, err:= refresh(context) if err == nil { context.JSON(http.StatusOK, gin.H{"code": 0, "token": singedToken}) } else { context.JSON(http.StatusOK, gin.H{"code": 1, "token": singedToken}) } }) router.Run()}
1、我们访问http://127.0.0.1:8080/login,获得token,结果如下
{ "code": 0, "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODM2NzQ2MzEsImlhdCI6MTU4MzY3MTAzMSwiVXNlciI6eyJJZCI6MSwiTmFtZSI6Imhhbnl1biJ9fQ.kMmE3DWXvNOUVsuHWgrlbm2pbsOHmbMtyr-V6hVjQ4s"}
2、访问http://127.0.0.1:8080/user,同时在header里面加入token,获得用户信息
postman示例如下
curl示例如下
curl --location --request GET 'http://127.0.0.1:8080/user' \--header 'token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODM2NzQ2MzEsImlhdCI6MTU4MzY3MTAzMSwiVXNlciI6eyJJZCI6MSwiTmFtZSI6Imhhbnl1biJ9fQ.kMmE3DWXvNOUVsuHWgrlbm2pbsOHmbMtyr-V6hVjQ4s'
结果如下
3、刷新token,访问http://127.0.0.1:8080/refresh
postman示例如下
curl请求示例如下
curl --location --request GET 'http://127.0.0.1:8080/refresh' \--header 'token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODM2NzQ2MzEsImlhdCI6MTU4MzY3MTAzMSwiVXNlciI6eyJJZCI6MSwiTmFtZSI6Imhhbnl1biJ9fQ.kMmE3DWXvNOUVsuHWgrlbm2pbsOHmbMtyr-V6hVjQ4s'