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

时间:2019-10-18 05:31:01

标签: 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)
    })
}

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

1 个答案:

答案 0 :(得分: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
   }
}

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