// util/jwt.go package util import ( "gindemo/pkg/setting" "time" "github.com/golang-jwt/jwt" ) var jwtSecret = []byte(setting.JwtSecret) //配置文件中自己配置的 // Claims是一些用户信息状态和额外的jwt参数 type Claims struct { Username string `json:"username"` Password string `json:"password"` jwt.StandardClaims } // 根据用户的用户名和密码参数token func GenerateToken(username, password string) (string, error) { nowTime := time.Now() expireTime := nowTime.Add(time.Minute * 15).Unix() claims := Claims{ Username: username, Password: password, StandardClaims: jwt.StandardClaims{ ExpiresAt: expireTime, // 过期时间 Issuer: "gindemo", //指定发行人 }, } // 该方法内部生成签名字符串,再用于获取完整、已签名的token tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) token, err := tokenClaims.SignedString(jwtSecret) return token, err } // 根据传入的token值获取到Claims对象信息(进而获取其中的用户名和密码) func ParseToken(token string) (*Claims, error) { // 用于解析鉴权的声明,方法内部主要是具体的解码和校验的过程,最终返回*Token tokenClaims, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) { return jwtSecret, nil }) if tokenClaims != nil { // 从tokenClaims中获取到Claims对象,并使用断言,将该对象转换为我们自己定义的Claims // 要传入指针,项目结构体都是用指针传递,节省空间 if claims, ok := tokenClaims.Claims.(*Claims); ok && tokenClaims.Valid { // Valid()验证基于时间的声明 return claims, nil } } return nil, err } // 中间件 // middleware/jwt/jwt.go package jwt import ( "gindemo/pkg/e" "gindemo/pkg/util" "net/http" "time" "github.com/gin-gonic/gin" ) // 自定义中间件 func JWT() gin.HandlerFunc { return func(c *gin.Context) { var code int var data interface{} code = e.SUCCESS token := c.Query("token") if token == "" { code = e.INVALID_PARAMS } else { // 解析token claims, err := util.ParseToken(token) if err != nil { code = e.ERROR_AUTH_CHECK_TOKEN_FAIL } else if time.Now().Unix() > claims.ExpiresAt { code = e.ERROR_AUTH_CHECK_TOKEN_TIMEOUT } } if code != e.SUCCESS { c.JSON(http.StatusUnauthorized, gin.H{ "code": code, "msg": e.GetMsg(code), "data": data, }) c.Abort() return } c.Next() } } // models/auth.go // 数据库查用户 package models type Auth struct { ID int `gorm:"primary_key" json:"id"` Username string `json:"username"` Password string `json:"password"` } func CheckAuth(username, password string) bool { var auth Auth db.Select("id").Where(Auth{Username: username, Password: password}).First(&auth) return auth.ID > 0 } // routers/api/auth.go // 用户认证逻辑视图 package api import ( "gindemo/models" "gindemo/pkg/e" "gindemo/pkg/util" "log" "net/http" "github.com/astaxie/beego/validation" "github.com/gin-gonic/gin" ) type auth struct { Username string `valid:"Required;MaxSize(50)"` Password string `valid:"Required;MaxSize(50)"` } func GetAuth(c *gin.Context) { username := c.Query("username") password := c.Query("password") valid := validation.Validation{} a := auth{Username: username, Password: password} ok, _ := valid.Valid(&a) data := make(map[string]interface{}) code := e.INVALID_PARAMS if ok { // 去数据库中查询用户是否存在 isExist := models.CheckAuth(username, password) if isExist { // 创建token token, err := util.GenerateToken(username, password) if err != nil { code = e.ERROR_AUTH_TOKEN } else { data["token"] = token code = e.SUCCESS } } else { code = e.ERROR_AUTH } } else { for _, err := range valid.Errors { log.Println(err.Key, err.Message) } } c.JSON(http.StatusOK, gin.H{ "code": code, "msg": e.GetMsg(code), "data": data, }) } // routers/router.go // 添加auth路由 package routers import ( "gindemo/middleware/jwt" "gindemo/pkg/setting" "gindemo/routers/api" v1 "gindemo/routers/api/v1" "github.com/gin-gonic/gin" ) func InitRouter() *gin.Engine { r := gin.New() r.Use(gin.Logger()) r.Use(gin.Recovery()) gin.SetMode(setting.RunMode) // 认证 r.GET("/auth", api.GetAuth) // 路由组 apiv1 := r.Group("/api/v1") { ... } return r } // 测试 http://127.0.0.1:8000/auth?username=test&password=test123456 // 返回数据 { "code": 200, "data": { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRlc3QiLCJwYXNzd29yZCI6InRlc3QxMjM0NTYiLCJleHAiOjE2NDYzMzc0NzMsImlzcyI6ImdpbmRlbW8ifQ.mFGXb6dyYFGIni3joNinfpsNmeDAvvDOFKSfvJ4ss1w" }, "msg": "ok" } // 将中间件接入Gin // routers/router.go package routers import ( "gindemo/middleware/jwt" "gindemo/pkg/setting" "gindemo/routers/api" v1 "gindemo/routers/api/v1" "github.com/gin-gonic/gin" ) func InitRouter() *gin.Engine { r := gin.New() r.Use(gin.Logger()) r.Use(gin.Recovery()) gin.SetMode(setting.RunMode) // 认证 r.GET("/auth", api.GetAuth) // 路由组 apiv1 := r.Group("/api/v1") // 使用中间件认证 apiv1.Use(jwt.JWT()) { ... } return r } // 以后每次请求的时候先获取Token,然后请求其他url的时候带上token就可以了