用Gin-JWT实现ROLE

时间:2019-03-22 17:45:10

标签: go jwt

我正在使用Golang中的GIN和Gin-JWT框架。 到目前为止,到目前为止,我已经能够按照Gin-JWT软件包中的示例使用JWT授权和认证我的REST API。

我现在正在尝试在我的API中实现某种角色。 流程为:

  1. 登录并验证
  2. 在userID和RoleID内部创建JWT
  3. 当我调用REST API时,我遇到了与该API关联的角色,并已将JWT中的RoleID授予授权

到目前为止,我的主要内容是:

jwtAfp := InitJwtMiddleware(db)
afb := r.Group("api/v1/afb")
afb.Use(jwtAfp.MiddlewareFunc())
afb.GET("/ping", afbController.Ping)

这是使用Gin-JWT的InitJwtMiddleware的

func InitJwtMiddleware(db *gorm.DB) *jwt.GinJWTMiddleware {
return &jwt.GinJWTMiddleware{
    Realm:      "afb",
    Key:        []byte("secret pwd"),
    Timeout:    time.Hour,
    MaxRefresh: time.Hour,
    PayloadFunc: func(data interface{}) jwt.MapClaims {
        if v, ok := data.(*model.User); ok {
            return jwt.MapClaims{
                "afb": v.ID,
            }
        }
        return jwt.MapClaims{}
    },
    Authenticator: func(c *gin.Context) (interface{}, error) {
        var loginVals login
        if err := c.Bind(&loginVals); err != nil {
            return "", jwt.ErrMissingLoginValues
        }
        email := loginVals.Username
        password := loginVals.Password
        var u model.User
        db.Where("email = ?", email).First(&u)
        if service.CheckPasswordHash(password, u.Password) {
            return &u, nil
        }

        return nil, jwt.ErrFailedAuthentication
    },
    Authorizator: func(data interface{}, c *gin.Context) bool {
        claims := jwt.ExtractClaims(c)
        v, ok := data.(float64)
        if ok && v == claims["afb"] {
            return true
        }
        return false
    },
    Unauthorized: func(c *gin.Context, code int, message string) {
        c.JSON(code, gin.H{
            "code":    code,
            "message": message,
        })
    },

    TokenHeadName: "Bearer",
    TimeFunc: time.Now,
}
}

我想在Authorizator部分中添加对Role的检查,但是我在如何做到这一点上苦苦挣扎。 我想同时传递InitJwtMiddleware(db)函数,这个函数可以工作,但是我不喜欢为每个ROLE / API“实例化”一个GinJWTMiddleware的想法。或者,如果我可以在中间件中知道稍后将调用哪个函数(控制器),那么我可以确定是否进行授权。但是,即使是这种甜味剂对我来说也很尴尬。我认为会有一个最优雅的解决方案,有什么想法吗?

1 个答案:

答案 0 :(得分:1)

您可以尝试以下方法:

https://github.com/kyfk/gin-jwt

这是最简单的auth [orization / entication]库。

VerifyPerm功能可能有助于角色管理。

有一个complete example

func main() {
    auth, err := jwt.New(jwt.Auth{
        SecretKey: []byte("must change here"),

        // Authenticator authenticates a request and return jwt.MapClaims
        // that contains a user information of the request.
        Authenticator: func(c *gin.Context) (jwt.MapClaims, error) {
            var loginForm LoginForm
            if err := c.ShouldBind(&loginForm); err != nil {
                return nil, jwt.ErrorAuthenticationFailed
            }

            u, ok := authenticate(req.Username, req.Password)
            if ok {
                return nil, jwt.ErrorAuthenticationFailed
            }

            return jwt.MapClaims{
                "username": u.Username,
                "role":     u.Role,
            }, nil
        },

        // UserFetcher takes a jwt.MapClaims and return a user object.
        UserFetcher: func(c *gin.Context, claims jwt.MapClaims) (interface{}, error) {
            username, ok := claims["username"].(string)
            if !ok {
                return nil, nil
            }
            return findByUsername(username)
        },
    })

    // some lines

    e.Use(jwt.ErrorHandler)

    // issue authorization token
    e.POST("/login", auth.AuthenticateHandler)

    // refresh token expiration
    e.POST("/auth/refresh_token", auth.RefreshHandler)

    // role management
    e.GET("/operator/hello", Operator(auth), SayHello) // this is only for Operator
    e.GET("/admin/hello", Admin(auth), SayHello) // this is only for Admin
}

func Operator(m jwt.Auth) gin.HandlerFunc {
    return m.VerifyPerm(func(claims jwt.MapClaims) bool {
        return role(claims).IsOperator()
    })
}

func Admin(m jwt.Auth) gin.HandlerFunc {
    return m.VerifyPerm(func(claims jwt.MapClaims) bool {
        return role(claims).IsAdmin()
    })
}