rest - 如何在中间件路由中应用角色

标签 rest go authorization middleware roles

我想使用golang中的角色设置中间件授权,以将某些API限制为角色,例如用于管理员访问所有API,用于worker1一些API

我已经通过jwt和中间件完成了授权,现在我正在尝试为角色添加代码

授权包

func Login(w http.ResponseWriter, r *http.Request) {
    user := &models.User{}
    err := json.NewDecoder(r.Body).Decode(user)
    if err != nil {
        var resp = map[string]interface{}{"status": false, "message": "Ivalid request"}
        json.NewEncoder(w).Encode(resp)
        return
    }
    resp := FindOne(user.Email, user.Password)
    json.NewEncoder(w).Encode(resp)
}
func FindOne(email, password string) map[string]interface{} {
    user := &models.User{}

    if err := database.DBGORM.Where("Email = ?", email).First(user).Error; err != nil {
        var resp = map[string]interface{}{"status": false, "message": "Email address not found"}
        return resp
    }
    expiresAt := time.Now().Add(time.Minute * 5).Unix()

    errf := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
    if errf != nil && errf == bcrypt.ErrMismatchedHashAndPassword { //Password does not match!
        var resp = map[string]interface{}{"status": false, "message": "Invalid login credentials. Please try again"}
        return resp
    }

    tk  := &models.Token{
        UserID: user.ID,
        Name:   user.Name,
        Email:  user.Email,
        Role: user.Role,
        StandardClaims: &jwt.StandardClaims{
            ExpiresAt: expiresAt,
        },
    }

    token := jwt.NewWithClaims(jwt.GetSigningMethod("HS256"), tk)

    tokenString, error := token.SignedString([]byte("secret"))
    if error != nil {
        fmt.Println(error)
    }

    var resp = map[string]interface{}{"status": false, "message": "logged in"}
    resp["token"] = tokenString //Store the token in the response
    return resp
}

JWT验证功能
func JwtVerify(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

        var header = r.Header.Get("x-access-token") //Grab the token from the header

        header = strings.TrimSpace(header)

        if header == "" {
            //Token is missing, returns with error code 403 Unauthorized
            w.WriteHeader(http.StatusForbidden)
            json.NewEncoder(w).Encode(Exception{Message: "Missing auth token"})
            return
        }
        tk := &models.Token{}

        _, err := jwt.ParseWithClaims(header, tk, func(token *jwt.Token) (interface{}, error) {
            return []byte("secret"), nil
        })

        if err != nil {
            w.WriteHeader(http.StatusForbidden)
            json.NewEncoder(w).Encode(Exception{Message: err.Error()})
            return
        }
        ctx := context.WithValue(r.Context(), "user", tk)
        next.ServeHTTP(w, r.WithContext(ctx)) 
    })
}

这是路线
func Handlers()  *mux.Router {

    router := mux.NewRouter().StrictSlash(true)
    router.Use(CommonMiddleWare)

    router.HandleFunc("/api/login", controller.Login)
    router.HandleFunc("/api/register", controller.CreateUser)
    router.HandleFunc("/api/getclientbylogin/login={login}", controller.GetNowClientHardwareByLogin).Methods("GET")
    router.HandleFunc("/api/getclientbyname/fullname={lname}&{fname}&{sname}", controller.GetProfilesByFullNames).Methods("GET")
    router.HandleFunc("/api/getaddress/{type}={value}", controller.GetLocation).Methods("GET")
    router.HandleFunc("/api/getfullnames/{type}", controller.GetNames).Methods("GET")
    router.HandleFunc("/api/operstatus={login}", controller.CheckEquipment).Methods("GET")
    router.HandleFunc("/api/cablediagnostic={login}", controller.CheckInventory).Methods("GET")

    s := router.PathPrefix("/auth").Subrouter()
    s.Use(utils.JwtVerify)
    s.HandleFunc("/api/getname/{type}={value}", controller.GetName).Methods("GET")


    return router
}
func CommonMiddleWare(next http.Handler) http.Handler  {
    return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
        res.Header().Add("Content-type", "application/json")
        res.Header().Set("Access-Control-Allow-Origin", "*")
        res.Header().Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE")
        res.Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, Access-Control-Request-Headers, Access-Control-Request-Method, Connection, Host, Origin, User-Agent, Referer, Cache-Control, X-header")
        next.ServeHTTP(res, req)
    })
}

如何实现此代码的角色?

最佳答案

我假设muxgorilla/mux。这与我在项目中正在做的事情很接近:

首先用以下名称注册路由:

router.HandleFunc("/api/register", controller.CreateUser).Name("createUser")

然后从中间件使用该名称进行角色/方法查找:
currentRoute:=mux.CurrentRoute(request)
if currentRoute!=nil {
   if !checkRole(ctx,currentRoute.GetName()) {
       // return 403
   }
}

其中checkRole是从ctx获取用户角色并使用查找表确定用户角色是否包括路由名称的函数。

关于rest - 如何在中间件路由中应用角色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58444488/

相关文章:

struct - 去解析yaml文件

html - 如何结合localStorage和sessionStorage的优势

WCF 服务授权管理器设置 Thread.CurrentPrincipal

rest - 匿名访问 REST API?

java - REST - 定义来自 Restful Java 服务的 JSON 数组的名称

php - 创建 REST API 客户端和服务器

Go 语言中的结构

sockets - 服务器未在 "Hello World"套接字程序中获取消息

c# - .NET Core API 项目中的分页

javascript - 在 Chrome 66 中向经过 NTLM 身份验证的服务器发出 API 请求