0

我想在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)
    })
}

我如何实现此代码的角色?

4

1 回答 1

1

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

首先使用名称注册路由:

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

然后使用中间件中的该名称进行角色/方法查找:

currentRoute:=mux.CurrentRoute(request)
if currentRoute!=nil {
   if !checkRole(ctx,currentRoute.GetName()) {
       // return 403
   }
}

wherecheckRole是一个从 ctx 获取用户角色的函数,并使用查找表来确定用户的角色是否包含路由名称。

于 2019-10-18T05:47:32.400 回答