在jwt-go 中我记录了手动封装一个认证中间件,然后今天在看go-admin 后台管理系统源码的时候发现作者用到了一个第三方库gin-jwt 实现了同样的功能,今天就一起来看一下吧!
gin-jwt能做什么?
源码分析 整个框架就一个auth_jwt.go 文件,共747行代码。我们从头往下看:
先定义了一个返回值为map类型的接口type MapClaims map[string]interface{}
接着就是一个结构体GinJWTMiddleware
,还记得我们在使用jwt-go的时候,也会定义一个结构体,里面存放了关于生成token的一些信息,包括:token发放时间、是谁发放的token、主题等,这里也一样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 type GinJWTMiddleware struct { // Realm name to display to the user. Required. Realm string // 算法类型: HS256, HS384, HS512默认是 HS256. SigningAlgorithm string // 加密密钥. Key []byte // 刷新Token有效期.默认一个小时 MaxRefresh time.Duration // 认证回调函数 Authenticator func(c *gin.Context) (interface{}, error) // 通过认证后的处理函数 Authorizator func(data interface{}, c *gin.Context) bool // 认证失败的回调函数 Unauthorized func(*gin.Context, int, string) //登录响应函数 LoginResponse func(*gin.Context, int, string, time.Time) // 超时响应函数 LogoutResponse func(*gin.Context, int) // 刷新响应函数 RefreshResponse func(*gin.Context, int, string, time.Time) }
函数(只列了几个目前见到的)
登录返回token
1 2 3 4 5 6 // LoginHandler can be used by clients to get a jwt token. // Payload needs to be json in the form of {"username" : "USERNAME" , "password" : "PASSWORD" }. // Reply will be of the form {"token" : "TOKEN" }. func (mw *GinJWTMiddleware) LoginHandler(c *gin.Context) { ... }
刷新token
1 2 3 4 5 6 7 8 9 10 11 12 // RefreshHandler can be used to refresh a token. The token still needs to be valid on refresh. // Shall be put under an endpoint that is using the GinJWTMiddleware. // Reply will be of the form {"token" : "TOKEN" }. func (mw *GinJWTMiddleware) RefreshHandler(c *gin.Context) { tokenString, expire, err := mw.RefreshToken(c) if err != nil { mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c)) return } mw.RefreshResponse(c, http.StatusOK, tokenString, expire) }
验证API时需要用到,例如检测权限
1 2 3 4 5 6 // MiddlewareFunc makes GinJWTMiddleware implement the Middleware interface. func (mw *GinJWTMiddleware) MiddlewareFunc() gin.HandlerFunc { return func(c *gin.Context) { mw.middlewareImpl(c) } }
示例 测试官方demo 源码地址:https://github.com/samtake/gin-jwt-demo
1 2 3 [GIN] 2020/04/18 - 18:29:51 | 200 | 1.502204ms | ::1 | POST "/login" [GIN] 2020/04/18 - 18:30:50 | 401 | 112.029µs | ::1 | GET "/auth/hello" [GIN] 2020/04/18 - 18:32:55 | 200 | 346.218µs | ::1 | GET "/auth/hello"
直接请求401
1 2 3 4 { "code" : 401, "message" : "cookie token is empty" }
登录返回token
1 2 3 4 5 { "code" : 200, "expire" : "2020-04-18T19:29:51+08:00" , "token" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1ODcyMDkzOTEsImlkIjoiYWRtaW4iLCJvcmlnX2lhdCI6MTU4NzIwNTc5MX0.o55urrL-qhUqpqEKK8k8KF8yBqrgZo_EtKmuOW1bHnc" }
携带token请求
1 2 3 4 5 { "text" : "Hello World." , "userID" : "admin" , "userName" : "admin" }
go-admin中的使用 这里也就记录别人在项目中是怎么使用的,以及有没有可以学习的地方。
auth.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package middleware import ( config2 "go-admin/config" "go-admin/handler" jwt "go-admin/pkg/jwtauth" "time" ) func AuthInit() (*jwt.GinJWTMiddleware, error) { return jwt.New(&jwt.GinJWTMiddleware{ Realm: "test zone" , Key: []byte("secret key" ), Timeout: time.Hour, MaxRefresh: time.Hour, IdentityKey: config2.ApplicationConfig.JwtSecret, PayloadFunc: handler.PayloadFunc, IdentityHandler: handler.IdentityHandler, Authenticator: handler.Authenticator, Authorizator: handler.Authorizator, Unauthorized: handler.Unauthorized, TokenLookup: "header: Authorization, query: token, cookie: jwt" , TokenHeadName: "Bearer" , TimeFunc: time.Now, }) }
permission.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package middleware import ( "github.com/gin-gonic/gin" "go-admin/pkg" mycasbin "go-admin/pkg/casbin" "go-admin/pkg/jwtauth" _ "go-admin/pkg/jwtauth" "log" "net/http" ) //权限检查中间件 func AuthCheckRole() gin.HandlerFunc { return func(c *gin.Context) { data, _ := c.Get("JWT_PAYLOAD" ) v := data.(jwtauth.MapClaims) e, err := mycasbin.Casbin() pkg.HasError(err,"" ,500) //检查权限 res, err := e.Enforce(v["rolekey" ], c.Request.URL.Path, c.Request.Method) log.Println("----------------" , v["rolekey" ], c.Request.URL.Path, c.Request.Method) pkg.HasError(err,"" ,500) if res { c.Next() } else { c.JSON(http.StatusOK, gin.H{ "status" : 401, "msg" : "对不起,您没有该接口访问权限,请联系管理员" , }) c.Abort() return } } }
router.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 func InitRouter() *gin.Engine { // the jwt middleware authMiddleware, err := middleware.AuthInit()//初始化 if err != nil { _ = fmt.Errorf("JWT Error" , err.Error()) } r.POST("/login" , authMiddleware.LoginHandler) //框架自带 // Refresh time can be longer than token timeout r.GET("/refresh_token" , authMiddleware.RefreshHandler)//框架自带 apiv1 := r.Group("/api/v1" ) { apiv1.GET("/monitor/server" , monitor.ServerInfo) ... } auth := r.Group("/api/v1" ) auth.Use(authMiddleware.MiddlewareFunc()).Use(middleware.AuthCheckRole())//检测权限 { auth.GET("/deptList" , system.GetDeptList) ... } }
写到最后发现这里有篇博客写的挺好的,可以看看~https://blog.firerain.me/article/18
.end