前面我们使用拦截器可以对想要用户登录的接口进行登录验证拦截,但是具体的代码没有完成,所以本文我们把jwt相关的内容给补充完毕。
1、添加依赖
使用jwt的话,需要使用到jwt-go框架,所以首先需要添加依赖。执行如下的命令
go get -u github.com/dgrijalva/jwt-go
2、编写jwtutils
使用jwt的话,我们一般集成一个自己写的utils类,然后在里面编写jwt的编码和接码相关的方法,因此这里我们在utils目录下创建一个jwtUtils.go文件,示例如下:
完整的代码示例如下:
package utils import ( "errors" "github.com/dgrijalva/jwt-go" "time" ) /* * 这里是我们准备在jwt中存储哪些字段,可以随意添加,这里我们只存储username即可 */ type MyClaims struct { Username string `json:"username"` jwt.StandardClaims } const TokenExpireDuration = time.Hour * 2 var MySecret = []byte("123456") /* * 生成jwt */ func GenToken(username string) (string, error) { // 创建一个我们自己的声明数据结构 c := MyClaims{ username, // 自定义字段 jwt.StandardClaims{ ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间 Issuer: "admin", // 签发人 }, } // 使用指定的签名方法创建签名对象 token := jwt.NewWithClaims(jwt.SigningMethodHS256, c) // 使用指定的secret签名并获得完整的编码后的字符串token return token.SignedString(MySecret) } /* * 解码jwt */ func ParseToken(tokenString string) (*MyClaims, error) { // 解析token token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (i interface{}, err error) { return MySecret, nil }) if err != nil { return nil, err } if claims, ok := token.Claims.(*MyClaims); ok && token.Valid { // 校验token return claims, nil } return nil, errors.New("invalid token") }
3、编写登录接口
接下来我们编写一个login的接口,用于用户登录,用户登录成功之后,我们生成jwt token返回给前端,首先我们创建一个request目录,再创建一个loginRequest.go文件,示例如下:
这主要是登录接口我们让前端传递json过来,这里使用loginRequest来接收json参数,loginRequest.go示例代码如下:
package request type LoginReuqest struct { Username string `json:"username"` password string `json:"password"` }
定义了request之后,我们还要定义response,我们希望返回的数据结构是一致的,所以这里创建一个response文件夹,再创建一个baseResponse.go文件,示例如下:
这里统一的返回格式示例是:
{ "Code": 200, "Msg": "请求成功", "Data": null }
对应的baseResponse.go示例代码如下:
package response type BaseResponse struct { Code int Msg string Data any }
然后我们在userController.go里面编写login的方法,示例代码如下:
package controllers import ( "awesomeProject/config" "awesomeProject/models" "awesomeProject/request" "awesomeProject/response" "awesomeProject/utils" "github.com/gin-gonic/gin" "log" "net/http" ) func RegisterUser(c *gin.Context) { var user models.User if err := c.ShouldBindJSON(&user); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } log.Println("请求了接口register接口") config.DB.Create(&user) c.JSON(http.StatusCreated, user) } func LoginUser(c *gin.Context) { loginRequest := request.LoginReuqest{} if err := c.ShouldBindJSON(&loginRequest); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } token, err := utils.GenToken(loginRequest.Username) if err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } rs := response.BaseResponse{ Code: http.StatusOK, Msg: "请求成功", Data: token, } c.JSON(http.StatusCreated, rs) }
然后把loginUser方法注册到路由里面去:
func SetupRouter() *gin.Engine { r := gin.Default() r.POST("/resgister", controllers.RegisterUser) r.POST("login", controllers.LoginUser) authorized := r.Group("/api") authorized.Use(middleware.AuthenticateJWT()) { authorized.GET("/listgoods", controllers.ListGoods) } return r }
这里生成的jwt模块的代码就完成了,咱们运行一下,请求login接口看看,示例图如下:
可以看到成功的生成了jwt的秘钥信息。
4、拦截解析jwt
前面我们生成了jwt,那么比如我们拦截的listgoods接口的时候就需要去拦截jwt的token,并且解析出对应的信息,因此我们需要对middleware包下的jwt.go文件进行改造,改造后的示例代码如下:
package middleware import ( "awesomeProject/utils" "github.com/gin-gonic/gin" "log" "net/http" ) func AuthenticateJWT() gin.HandlerFunc { return func(c *gin.Context) { tokenString := c.GetHeader("Authorization") if tokenString == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header required"}) c.Abort() return } chain, err := utils.ParseToken(tokenString) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()}) c.Abort() return } log.Println("获取到当前登录用户的用户名是:", chain.Username) c.Set("username", chain.Username) c.Next() } }
上面的代码流程是从header头里面获取key为Authorization的jwt信息,然后使用jwt进行解码,解码后就可以获取到Myclaim对象,然后就可以获取到我们存在Myclaim里面的信息了。
这里我们获取到username之后,还可以通过gin.Context对象把用户信息传递下去,在之后的代码里面可以直接在gin.Context对象中获取到用户信息。
接着我们修改下goodsController.go文件
把接口改造一下,完整代码示例如下:
package controllers import ( "awesomeProject/response" "github.com/gin-gonic/gin" "log" "net/http" ) func ListGoods(c *gin.Context) { username, _ := c.Get("username") log.Println("通过中间件解析获取到的username是:", username) rs := response.BaseResponse{ http.StatusOK, "请求成功", "获取商品列表成功", } c.JSON(http.StatusOK, rs) }
最后我们启动项目,进行测试:
可以看到通过jwt的拦截,我们成功的访问了listgoods接口,最后我们再看看日志:
可以看到通过jwt进行解码之后,获取到了我们存储的username值。
以上就是在gin web中添加jwt相关代码的完整案例。
最后附上本案例的源码,登录后即可下载
还没有评论,来说两句吧...