使用JWT做RESTful API的身份验证-Go语言实现

栏目: 编程工具 · 发布时间: 6年前

内容简介:在需要先安装go http的中间件实现起来很简单,只需要实现一个函数签名为func(http.Handler) http.Handler的函数即可。

使用Golang和 MongoDB 构建 RESTful API 已经实现了一个简单的 RESTful API应用,但是对于有些API接口需要授权之后才能访问,在这篇文章中就用 jwt 做一个基于Token的身份验证,关于 jwt 请访问JWT有详细的说明,而且有各个语言实现的库,请根据需要使用对应的版本。

使用JWT做RESTful API的身份验证-Go语言实现

需要先安装 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


以上所述就是小编给大家介绍的《使用JWT做RESTful API的身份验证-Go语言实现》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Go Web 编程

Go Web 编程

[新加坡]Sau Sheong Chang(郑兆雄) / 黄健宏 / 人民邮电出版社 / 2017-11-22 / 79

《Go Web 编程》原名《Go Web Programming》,原书由新加坡开发者郑兆雄(Sau Sheong Chang)创作、 Manning 出版社出版,人名邮电出版社引进了该书的中文版权,并将其交由黄健宏进行翻译。 《Go Web 编程》一书围绕一个网络论坛 作为例子,教授读者如何使用请求处理器、多路复用器、模板引擎、存储系统等核心组件去构建一个 Go Web 应用,然后在该应用......一起来看看 《Go Web 编程》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

在线进制转换器
在线进制转换器

各进制数互转换器

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器