做个笔记,没有连数据库,没有存redis,只是demo
package main
import (
"errors"
"fmt"
"log"
"net/http"
"strings"
"time"
"github.com/dgrijalva/jwt-go/v4"
"github.com/gin-gonic/gin"
)
type Users struct {
Username string `json:"username"`
Password string `json:"password"`
}
type CustomClaims struct {
Users
jwt.StandardClaims
}
var MySecret = []byte("密钥")
// 创建 Token
func GenToken(user Users) (string, error) {
claim := CustomClaims{
user,
jwt.StandardClaims{
ExpiresAt: jwt.At(time.Now().Add(time.Minute * 5)), //5分钟后过期
Issuer: "xx", //签发人
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claim)
return token.SignedString(MySecret)
}
// 解析 token
func ParseToken(tokenStr string) (*CustomClaims, error) {
token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
return MySecret, nil
})
if err != nil {
fmt.Println(" token parse err:", err)
return nil, err
}
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
return claims, nil
}
return nil, errors.New("invalid token")
}
// 刷新 Token
func RefreshToken(tokenStr string) (string, error) {
jwt.TimeFunc = func() time.Time {
return time.Unix(0, 0)
}
token, err := jwt.ParseWithClaims(tokenStr, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
return MySecret, nil
})
if err != nil {
return "", err
}
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
jwt.TimeFunc = time.Now
claims.StandardClaims.ExpiresAt = jwt.At(time.Now().Add(time.Minute * 10))
return GenToken(claims.Users)
}
return "", errors.New("Cloudn't handle this token")
}
// JWTAuth 中间件,检查token
func JWTAuth() gin.HandlerFunc {
return func(ctx *gin.Context) {
authHeader := ctx.Request.Header.Get("Authorization")
if authHeader == "" {
ctx.JSON(http.StatusOK, gin.H{
"code": -1,
"msg": "无权限访问,请求未携带token",
})
ctx.Abort() //结束后续操作
return
}
log.Print("token:", authHeader)
//按空格拆分
parts := strings.SplitN(authHeader, " ", 2)
if !(len(parts) == 2 && parts[0] == "Bearer") {
ctx.JSON(http.StatusOK, gin.H{
"code": -1,
"msg": "请求头中auth格式有误",
})
ctx.Abort()
return
}
//解析token包含的信息
claims, err := ParseToken(parts[1])
if err != nil {
ctx.JSON(http.StatusOK, gin.H{
"code": -1,
"msg": "无效的Token",
})
ctx.Abort()
return
}
// 将当前请求的claims信息保存到请求的上下文c上
ctx.Set("claims", claims)
ctx.Next() // 后续的处理函数可以用过ctx.Get("claims")来获取当前请求的用户信息
}
}
func LoginController(ctx *gin.Context) {
username := ctx.Query("username")
password := ctx.Query("password")
if !(username == "admin" && password == "123456") {
ctx.JSON(http.StatusOK, gin.H{
"code": -1,
"msg": "用户名或密码错误",
})
return
}
user := Users{
Username: "admin",
Password: "123456",
}
//生成token
token, err := GenToken(user)
if err != nil {
ctx.JSON(http.StatusOK, gin.H{
"code": -1,
"msg": err,
})
return
}
ctx.JSON(http.StatusOK, gin.H{
"code": 0,
"msg": "成功",
"data": gin.H{"token": token},
})
}
func UserListController(ctx *gin.Context) {
ctx.JSON(http.StatusOK, gin.H{
"code": 1,
"msg": "成功",
"data": "[]",
})
}
func main() {
r := gin.Default()
//路由
r.GET("/login", LoginController)
//使用中间件
r.Use(JWTAuth())
//获取列表数据
r.GET("/list", UserListController)
r.Run()
}