Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

different Authorizator depending on Router Groups #25

Open
philippecarle opened this issue Apr 18, 2016 · 5 comments
Open

different Authorizator depending on Router Groups #25

philippecarle opened this issue Apr 18, 2016 · 5 comments

Comments

@philippecarle
Copy link

Hi,

(thx for having merged so quickly my PR on Context injection ^^)

I'm facing an issue, and I think it may be a functional / logical problem in Authorization implementation and / or limitations cause by lack of informations about groups in gin.Context.

For example, here are my groups definitions for admin/users :

    admin := r.Group("/admin")
    admin.Use(authMiddleware.MiddlewareFunc())
    {
        users := admin.Group("/users")
        users.GET("/:username", user.ByUsernameHandler)
        users.POST("", registration.RegisterHandler)
        users.GET("", user.AllUsersHandler)
    }

By using your Authorizator callback, I have to be aware of two informations :

  • roles of user (stored in my DB)
  • which route matches to the request and in which group(s) it belongs

Each leads me to an issue :

  • User roles can be accessed only by querying for the second time (it has already been queried in Authenticator Handler). I've been trying to set user in context with c.Set("User", user) in Authenticator and access it in Authorizator, but unsuccessfully, c.Get return false for "exists" return param…
  • gin.Context does not contain Group… Just handler name…

Should I implement my own solution like writing a specific Middleware, with an string argument telling me what group is called ? Or is there any more elegant way to fix this ?

@gonboy
Copy link

gonboy commented Dec 13, 2017

maybe you can use belown method

func xxAuthorizator func(userID string, c *gin.Context) bool {
    claims := jwt.ExtractClaims(c)
    //.... get token and do your things
}

@arrwhidev
Copy link

arrwhidev commented Dec 1, 2018

Hi @philippecarle, or anyone else, did you find an elegant solution to this?

I also would like to pass a different Authorizator function for different groups, ideally without creating multiple middlewares.

Thanks!

@anarqz
Copy link

anarqz commented Mar 15, 2019

@arrwhidev you can create a single middleware and switch between its parameter:

func GroupAuthorizator(group string) gin.HandlerFunc {
	return func(c *gin.Context) {
		switch group {
		case "product":
			usr, _ := c.Get("id")
			fmt.Println(usr.(*models.User).UserName)
			c.Next()
                        return
		default:
			jwt.Unauthorized(c, http.StatusForbidden, jwt.HTTPStatusMessageFunc(jwt.ErrForbidden, c))
		}
	}
}

And then, create your gin group router like this:

t := &ProductRouter{}
tR := r.Group("/product")
tR.Use(jwt.MiddlewareFunc(), GroupAuthorizator("product"))
tR.GET("/", t.GetProduct)

@tomriddle1234
Copy link

@alcmoraes, could you be more detailed ? how to distinguish normal user, admin user, guest user?

usr, _ := c.Get("id")
fmt.Println(usr.(*models.User).UserName)
c.Next()
return

Could you explain these lines ?

@tomriddle1234
Copy link

tomriddle1234 commented May 18, 2019

Currently I hacked in the gin-jwt source code, like this, to by pass the authenticator function for normal users, so I achieved 3 roles, normal user, admin, and guest without login

// NormalMiddlewareFunc makes GinJWTMiddleware implement the Middleware interface by pass the admin identity check
func (mw *GinJWTMiddleware) NormalMiddlewareFunc() gin.HandlerFunc {
	return func(c *gin.Context) {
		mw.normalMiddlewareImpl(c)
	}
}

func (mw *GinJWTMiddleware) normalMiddlewareImpl(c *gin.Context) {
	claims, err := mw.GetClaimsFromJWT(c)
	if err != nil {
		mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(err, c))
		return
	}

	if claims["exp"] == nil {
		mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrMissingExpField, c))
		return
	}

	if _, ok := claims["exp"].(float64); !ok {
		mw.unauthorized(c, http.StatusBadRequest, mw.HTTPStatusMessageFunc(ErrWrongFormatOfExp, c))
		return
	}

	if int64(claims["exp"].(float64)) < mw.TimeFunc().Unix() {
		mw.unauthorized(c, http.StatusUnauthorized, mw.HTTPStatusMessageFunc(ErrExpiredToken, c))
		return
	}

	c.Set("JWT_PAYLOAD", claims)
	identity := mw.IdentityHandler(c)

	if identity != nil {
		c.Set(mw.IdentityKey, identity)
	}

	c.Next()
}

Then I used such middleware function like,

	knowledgeRoutes := router.Group("/data")
	{
		knowledgeRoutes.Use(jwtMiddleware.NormalMiddlewareFunc())
		{
			//these fetch functions record statistics
			knowledgeRoutes.GET("/getknowledgelist",  getKnowledgeListHandler)
			knowledgeRoutes.GET("/getallknowledge", getAllKnowledgeHandler)
			knowledgeRoutes.GET("/getknowledge/:name", getKnowledgeByNameHandler)
			knowledgeRoutes.GET("/getknowledgelogo/:name", getKnowledgeLogoHandler)
			knowledgeRoutes.POST("/searchknowledge/:keyword", searchKnowledgeKeywordHandler)
		}

	}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants