使用JWT做RESTful API的身分識別驗證-Go語言實現

來源:互聯網
上載者:User

使用JWT做RESTful API的身分識別驗證-Go語言實現

在 使用Golang和MongoDB構建 RESTful API已經實現了一個簡單的 RESTful API應用,但是對於有些API介面需要授權之後才能訪問,在這篇文章中就用 jwt 做一個基於Token的身分識別驗證,關於 jwt 請訪問 JWT有詳細的說明,而且有各個語言實現的庫,請根據需要使用對應的版本。

image

需要先安裝 jwt-go 介面 go get github.com/dgrijalva/jwt-go

新增註冊登入介面,並在登入時產生token

  • 自訂返回結果,並封裝 helper/utils.go
type Response struct {    Code int         `json:"code"`    Msg  string      `json:"msg"`    Data interface{} `json:"data"`}func ResponseWithJson(w http.ResponseWriter, code int, payload interface{}) {    response, _ := json.Marshal(payload)    w.Header().Set("Content-Type", "application/json")    w.WriteHeader(code)    w.Write(response)}
  • 模型 models/user.go
type User struct {    UserName string `bson:"username" json:"username"`    Password string `bson:"password" json:"password"`}type JwtToken struct {    Token string `json:"token"`}
  • 控制器 controllers/user.go
func Register(w http.ResponseWriter, r *http.Request) {    var user models.User    err := json.NewDecoder(r.Body).Decode(&user)    if err != nil || user.UserName == "" || user.Password == "" {        helper.ResponseWithJson(w, http.StatusBadRequest,            helper.Response{Code: http.StatusBadRequest, Msg: "bad params"})        return    }    err = models.Insert(db, collection, user)    if err != nil {        helper.ResponseWithJson(w, http.StatusInternalServerError,            helper.Response{Code: http.StatusInternalServerError, Msg: "internal error"})    }}func Login(w http.ResponseWriter, r *http.Request) {    var user models.User    err := json.NewDecoder(r.Body).Decode(&user)    if err != nil {        helper.ResponseWithJson(w, http.StatusBadRequest,            helper.Response{Code: http.StatusBadRequest, Msg: "bad params"})    }    exist := models.IsExist(db, collection, bson.M{"username": user.UserName})    if exist {        token, _ := auth.GenerateToken(&user)        helper.ResponseWithJson(w, http.StatusOK,            helper.Response{Code: http.StatusOK, Data: models.JwtToken{Token: token}})    } else {        helper.ResponseWithJson(w, http.StatusNotFound,            helper.Response{Code: http.StatusNotFound, Msg: "the user not exist"})    }}
  • 產生Token auth/middleware.go
func GenerateToken(user *models.User) (string, error) {    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{        "username": user.UserName,    //"exp":      time.Now().Add(time.Hour * 2).Unix(),// 可以添加到期時間    })    return token.SignedString([]byte("secret"))//對應的字串請自行產生,最後足夠使用加密後的字串}

http中介軟體

go http的中介軟體實現起來很簡單,只需要實現一個函數簽名為func(http.Handler) http.Handler的函數即可。

func middlewareHandler(next http.Handler) http.Handler{    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){        // 執行handler之前的邏輯        next.ServeHTTP(w, r)        // 執行完畢handler後的邏輯    })}

我們使用的 mux 作為路由,本身支援在路由中添加中介軟體,改造一下之前的路由邏輯

routes/routes.go

type Route struct {    Method     string    Pattern    string    Handler    http.HandlerFunc    Middleware mux.MiddlewareFunc //添加中介軟體}func NewRouter() *mux.Router {    router := mux.NewRouter()    for _, route := range routes {        r := router.Methods(route.Method).            Path(route.Pattern)    //如果這個路由有中介軟體的邏輯,需要通過中介軟體先處理一下        if route.Middleware != nil {            r.Handler(route.Middleware(route.Handler))        } else {            r.Handler(route.Handler)        }    }    return router}

實現身分識別驗證的中介軟體

auth/middleware.go

驗證的資訊放在http Header

func TokenMiddleware(next http.Handler) http.Handler {    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {        tokenStr := r.Header.Get("authorization")        if tokenStr == "" {            helper.ResponseWithJson(w, http.StatusUnauthorized,                helper.Response{Code: http.StatusUnauthorized, Msg: "not authorized"})        } else {            token, _ := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {                if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {                    helper.ResponseWithJson(w, http.StatusUnauthorized,                        helper.Response{Code: http.StatusUnauthorized, Msg: "not authorized"})                    return nil, fmt.Errorf("not authorization")                }                return []byte("secret"), nil            })            if !token.Valid {                helper.ResponseWithJson(w, http.StatusUnauthorized,                    helper.Response{Code: http.StatusUnauthorized, Msg: "not authorized"})            } else {                next.ServeHTTP(w, r)            }        }    })}

對需要驗證的路由添加中介軟體

register("GET", "/movies", controllers.AllMovies, auth.TokenMiddleware) //需要中介軟體邏輯register("GET", "/movies/{id}", controllers.FindMovie, nil)//不需要中介軟體

驗證

  • 登入之後,返回對應的token資訊
//請求 post http://127.0.0.1:8080/login//返回{    "code": 200,    "msg": "",    "data": {        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNvZGVybWluZXIifQ.pFzJLU8vnzWiweFKzHRsawyWA2jfuDIPlDU4zE92O7c"    }}
  • 擷取所有的電影資訊時
//請求 post http://127.0.0.1:8080/movies在 Header中設定 "authorization":token如果沒有設定header會報 401 錯誤{    "code": 401,    "msg": "not authorized",    "data": null}

源碼 Github

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.