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

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

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

需要先安装 jwt-go 接口 go get github.com/dgrijalva/jwt-go
新增注册登录接口,并在登录时生成token

自定义返回结果,并封装 helper/utils.go

1type Response struct {
 2    Code int         `json:"code"`
 3    Msg  string      `json:"msg"`
 4    Data interface{} `json:"data"`
 5}
 6
 7func ResponseWithJson(w http.ResponseWriter, code int, payload interface{}) {
 8    response, _ := json.Marshal(payload)
 9    w.Header().Set("Content-Type", "application/json")
10    w.WriteHeader(code)
11    w.Write(response)
12}

模型 models/user.go

1type User struct {
2    UserName string `bson:"username" json:"username"`
3    Password string `bson:"password" json:"password"`
4}type JwtToken struct {
5    Token string `json:"token"`
6}

控制器 controllers/user.go

1func Register(w http.ResponseWriter, r *http.Request) {
 2    var user models.User
 3    err := json.NewDecoder(r.Body).Decode(&user)    if err != nil || user.UserName == "" || user.Password == "" {
 4        helper.ResponseWithJson(w, http.StatusBadRequest,
 5            helper.Response{Code: http.StatusBadRequest, Msg: "bad params"})        return
 6    }
 7    err = models.Insert(db, collection, user)   if err != nil {
 8        helper.ResponseWithJson(w, http.StatusInternalServerError,
 9            helper.Response{Code: http.StatusInternalServerError, Msg: "internal error"})
10    }
11}
12
13func Login(w http.ResponseWriter, r *http.Request) {
14    var user models.User
15    err := json.NewDecoder(r.Body).Decode(&user)    if err != nil {
16        helper.ResponseWithJson(w, http.StatusBadRequest,
17            helper.Response{Code: http.StatusBadRequest, Msg: "bad params"})
18    }
19    exist := models.IsExist(db, collection, bson.M{"username": user.UserName})  if exist {
20        token, _ := auth.GenerateToken(&user)
21        helper.ResponseWithJson(w, http.StatusOK,
22            helper.Response{Code: http.StatusOK, Data: models.JwtToken{Token: token}})
23    } else {
24        helper.ResponseWithJson(w, http.StatusNotFound,
25            helper.Response{Code: http.StatusNotFound, Msg: "the user not exist"})
26    }
27}

生成Token auth/middleware.go

1func GenerateToken(user *models.User) (string, error) {
2    token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{       "username": user.UserName,
3    //"exp":      time.Now().Add(time.Hour * 2).Unix(),// 可以添加过期时间
4    })  return token.SignedString([]byte("secret"))//对应的字符串请自行生成,最后足够使用加密后的字符串
5}

http中间件
go http的中间件实现起来很简单,只需要实现一个函数签名func(http.Handler) http.Handler的函数即可。

1func middlewareHandler(next http.Handler) http.Handler{    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request){
2        // 执行handler之前的逻辑
3        next.ServeHTTP(w, r)
4        // 执行完毕handler后的逻辑
5    })
6}

我们使用的 mux 作为路由,本身支持在路由中添加中间件,改造一下之前的路由逻辑
routes/routes.go

1type Route struct {
2    Method     string
3    Pattern    string
4    Handler    http.HandlerFunc
5    Middleware mux.MiddlewareFunc //添加中间件
6}
7
8func NewRouter() *mux.Router {
9    router := mux.NewRouter()   for _, route := range routes {
10        r := router.Methods(route.Method).
11            Path(route.Pattern)
12    //如果这个路由有中间件的逻辑,需要通过中间件先处理一下        if route.Middleware != nil {
13            r.Handler(route.Middleware(route.Handler))
14        } else {
15            r.Handler(route.Handler)
16        }
17    }   return router
18}

实现身份验证的中间件
auth/middleware.go
验证的信息放在http Header中

1func TokenMiddleware(next http.Handler) http.Handler {    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 2        tokenStr := r.Header.Get("authorization")       if tokenStr == "" {
 3            helper.ResponseWithJson(w, http.StatusUnauthorized,
 4                helper.Response{Code: http.StatusUnauthorized, Msg: "not authorized"})
 5        } else {
 6            token, _ := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {               if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
 7                    helper.ResponseWithJson(w, http.StatusUnauthorized,
 8                        helper.Response{Code: http.StatusUnauthorized, Msg: "not authorized"})                  return nil, fmt.Errorf("not authorization")
 9                }               return []byte("secret"), nil
10            })          if !token.Valid {
11                helper.ResponseWithJson(w, http.StatusUnauthorized,
12                    helper.Response{Code: http.StatusUnauthorized, Msg: "not authorized"})
13            } else {
14                next.ServeHTTP(w, r)
15            }
16        }
17    })
18}

对需要验证的路由添加中间件

1register("GET", "/movies", controllers.AllMovies, auth.TokenMiddleware) //需要中间件逻辑
2register("GET", "/movies/{id}", controllers.FindMovie, nil)//不需要中间件复制代码

验证
登录之后,返回对应的token信息

1//请求 post http://127.0.0.1:8080/login
2//返回
3
4{    "code": 200,    "msg": "",    "data": {        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImNvZGVybWluZXIifQ.pFzJLU8vnzWiweFKzHRsawyWA2jfuDIPlDU4zE92O7c"
5    }
6}

获取所有的电影信息时

1//请求 post http://127.0.0.1:8080/movies
2在 Header中设置 "authorization":token
3如果没有设置header会报 401 错误
4
5{    "code": 401,    "msg": "not authorized",    "data": null
6}

源码 Github

原文发布时间为:2018-07-19
本文作者:CoderMiner
本文来自云栖社区合作伙伴“Golang语言社区”,了解相关信息可以关注“Golang语言社区

相关文章
|
7天前
|
缓存 监控 API
构建高效可扩展的RESTful API:后端开发的实践指南
【4月更文挑战第26天】在现代Web开发中,构建一个高效、可扩展且易于维护的RESTful API是后端工程师必须面对的挑战。本文将深入探讨如何利用最佳实践和流行技术,设计出符合REST架构原则的服务端接口。我们将重点讨论API版本控制、资源路由、数据库优化、缓存策略以及安全性考虑等方面,旨在为开发者提供一套综合性解决方案,帮助其提升API的性能与可靠性。
|
3天前
|
JSON API 数据处理
【Swift开发专栏】Swift中的RESTful API集成实战
【4月更文挑战第30天】本文探讨了在Swift中集成RESTful API的方法,涉及RESTful API的基础概念,如HTTP方法和设计原则,以及Swift的网络请求技术,如`URLSession`、`Alamofire`和`SwiftyJSON`。此外,还强调了数据处理、错误管理和异步操作的重要性。通过合理利用这些工具和策略,开发者能实现高效、稳定的API集成,提升应用性能和用户体验。
|
3天前
|
缓存 监控 JavaScript
Node.js中构建RESTful API的最佳实践
【4月更文挑战第30天】本文介绍了在Node.js中构建RESTful API的最佳实践:选择合适的框架(如Express、Koa)、设计清晰的API接口(遵循HTTP动词和资源路径)、实现认证授权(JWT、OAuth 2.0)、错误处理、限流缓存、编写文档和测试,以及监控性能优化。这些实践有助于创建健壮、可维护和易用的API。
|
3天前
|
存储 关系型数据库 Go
【Go语言专栏】基于Go语言的RESTful API开发
【4月更文挑战第30天】本文介绍了使用Go语言开发RESTful API的方法,涵盖了路由、请求处理、数据存储和测试关键点。RESTful API基于HTTP协议,无状态且使用标准方法表示操作。在Go中,通过第三方库如`gorilla/mux`进行路由映射,使用`net/http`处理请求,与数据库交互可选ORM库`gorm`,测试则依赖于Go内置的`testing`框架。Go的简洁性和并发性使得它成为构建高效API的理想选择。
|
4天前
|
机器学习/深度学习 算法 安全
深度学习在图像识别中的应用与挑战构建高效可扩展的RESTful API:后端开发的实战指南
【4月更文挑战第30天】 随着计算机视觉技术的飞速发展,深度学习在图像识别领域取得了显著的成果。本文将探讨深度学习技术在图像识别中的应用及其所面临的挑战。首先,我们将介绍深度学习的基本原理和关键技术,然后分析其在图像识别中的优势和应用案例。最后,我们将讨论当前深度学习在图像识别领域所面临的主要挑战和未来的发展趋势。
|
4天前
|
XML JSON API
【PHP开发专栏】PHP RESTful API设计与开发
【4月更文挑战第29天】本文探讨了在Web开发中流行的前后端分离模式,重点介绍了RESTful API的设计与实现。REST是一种基于HTTP协议的架构风格,核心概念包括资源、表述和状态转换。RESTful API设计遵循无状态、统一接口等原则,使用GET、POST、PUT、DELETE等HTTP方法执行操作,并通过状态码和JSON/XML传输数据。在PHP中实现RESTful API,可通过定义路由、创建控制器、处理请求和响应,同时注意安全性措施,如使用HTTPS。文中还提供了一个用户管理API的实战示例,以帮助读者更好地理解和应用RESTful API。
|
4天前
|
缓存 监控 API
|
5天前
|
JSON 安全 API
【专栏】浅谈 REST API 身份验证的四种方法
【4月更文挑战第28天】本文探讨了四种REST API身份验证方法:基本认证、OAuth、JSON Web Token(JWT)和API密钥。基本认证简单但不安全;OAuth适用于授权第三方应用;JWT提供安全的身份验证信息传递;API密钥适合内部使用。选择方法时需平衡安全性、用户体验和开发复杂性。
|
9天前
|
缓存 安全 API
构建高效可扩展的RESTful API:后端架构的艺术
【4月更文挑战第25天】 在数字化时代的浪潮中,一个稳定、高效且易于扩展的后端系统是企业成功的关键。本文将探讨如何构建一个满足现代业务需求的RESTful API。我们将深入分析关键设计原则,如模块化、服务分层、缓存策略以及数据库优化,并讨论这些原则如何融入实际开发流程中。通过具体案例和最佳实践,我们的目标是为读者提供一套实用的工具和方法,以支持他们自己的后端开发工作。
|
12天前
|
缓存 JSON 负载均衡
构建高效RESTful API的最佳实践
【4月更文挑战第22天】在当今互联网应用的开发中,后端系统的核心通常体现在API的设计和实现上。一个设计良好、性能优异的RESTful API能够极大地提升应用的响应速度及用户体验。本文将探讨在构建高效RESTful API时应当遵循的一系列最佳实践,包括合理的数据结构设计、缓存策略、负载均衡技术以及API版本管理等。通过这些实践,可以确保API服务的高性能与易维护性,并适应不断变化的业务需求。