dsgixl5195 2016-11-18 14:05
浏览 72

Go服务器中基于角色的优雅JWT安全性

I'm writing a Go web API which uses JWT for tokens/auth etc. and I was wondering if there was a more elegant way of providing varying levels of access to my route handlers than the following?

package main

import (
    "net/http"

    "github.com/gin-gonic/gin"
    jwt "gopkg.in/appleboy/gin-jwt.v2"
)

var (
    users = map[string]byte{
        "admin":    1,
        "manager":  2,
        "employee": 3,
    }
)

func main() {
    router := gin.Default()
    group := router.Group("/v1")

    jwtMiddleware := &jwt.GinJWTMiddleware{
        Realm:         "realm",
        Key:           []byte("password"),
        Authenticator: authenticate,
        PayloadFunc:   payload,
    }

    group.Use(jwtMiddleware.MiddlewareFunc())
    group.GET("/refreshToken", jwtMiddleware.RefreshHandler)
    group.GET("/hello", hello)

    router.POST("/login", jwtMiddleware.LoginHandler)
    router.Run(":1234")
}

func hello(c *gin.Context) {
    switch getRoleFromContext(c) {
    case 1:
        helloAdmin(c)
    case 2:
        helloManager(c)
    case 3:
        helloEmployee(c)
    default:
        c.AbortWithStatus(http.StatusForbidden)
    }
}

func helloAdmin(c *gin.Context)    { c.String(http.StatusOK, "Hello, admin!") }
func helloManager(c *gin.Context)  { c.String(http.StatusOK, "Hello, manager!") }
func helloEmployee(c *gin.Context) { c.String(http.StatusOK, "Hello, employee!") }

func authenticate(email string, password string, c *gin.Context) (string, bool) {
    if _, ok := users[email]; ok {
        return email, true
    }

    return "", false
}

func payload(email string) map[string]interface{} {
    return map[string]interface{}{
        "role": users[email],
    }
}

func getRoleFromContext(c *gin.Context) (role byte) {
    claims := jwt.ExtractClaims(c)

    rawRole, ok := claims["role"]
    if !ok {
        c.AbortWithStatus(http.StatusForbidden)
    }

    floatRole, ok := rawRole.(float64)
    if !ok {
        c.AbortWithStatus(http.StatusForbidden)
    }

    return byte(floatRole)
}

In my real code (consisting of only 18 or so routes), I've created a Routes struct, which provides handlers for all of the routes my API provides. Within that, I'm performing the above switching logic to specialised Route structs, which ensures only administrative users can perform specific functions, while other functions are callable by multiple types of users, just with different behaviour.

I've tried throwing together middleware-based auth as follows:

func roleCheckerMiddleware(roles ...byte) gin.HandlerFunc {
    return func(c *gin.Context) {
        contextRole := getRoleFromContext(c)
        for _, role := range roles {
            if contextRole == role {
                c.Next()
                return
            }
        }

        c.AbortWithStatus(http.StatusForbidden)
    }
}

...and applying it as follows:

adminGroup := group.Group("/")
adminGroup.GET("/hello", helloAdmin)
adminGroup.Use(roleCheckerMiddleware(1))

managerGroup := group.Group("/")
managerGroup.GET("/hello", helloManager)
managerGroup.Use(roleCheckerMiddleware(2, 1))

employeeGroup := group.Group("/")
employeeGroup.GET("/hello", helloEmployee)
employeeGroup.Use(roleCheckerMiddleware(3, 2, 1))

...but the obvious duplication of the /hello route means this method isn't (as far as I'm aware) possible, without the introduction of groupings for /admin, /manager and /employee. I'd love to be shown otherwise though as this feels more elegant that my switching logic!

  • 写回答

1条回答 默认 最新

  • dousi4950 2018-03-23 17:38
    关注

    I find working with it using JWT and/or Session/Cookie based authentication mechanisms also very simple as. I hope this helps.

    评论

报告相同问题?

悬赏问题

  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP