使用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语言社区

相关文章
|
4天前
|
安全 Java API
RESTful API设计与实现:Java后台开发指南
【4月更文挑战第15天】本文介绍了如何使用Java开发RESTful API,重点是Spring Boot框架和Spring MVC。遵循无状态、统一接口、资源标识和JSON数据格式的设计原则,通过创建控制器处理HTTP请求,如示例中的用户管理操作。此外,文章还提及数据绑定、验证、异常处理和跨域支持。最后,提出了版本控制、安全性、文档测试以及限流和缓存的最佳实践,以确保API的稳定、安全和高效。
|
7天前
|
小程序 前端开发 API
小程序全栈开发中的RESTful API设计
【4月更文挑战第12天】本文探讨了小程序全栈开发中的RESTful API设计,旨在帮助开发者理解和掌握相关技术。RESTful API基于REST架构风格,利用HTTP协议进行数据交互,遵循URI、客户端-服务器架构、无状态通信、标准HTTP方法和资源表述等原则。在小程序开发中,通过资源建模、设计API接口、定义资源表述及实现接口,实现前后端高效分离,提升开发效率和代码质量。小程序前端利用微信API与后端交互,确保数据流通。掌握这些实践将优化小程序全栈开发。
|
16天前
|
前端开发 Java API
构建RESTful API:Java中的RESTful服务开发
【4月更文挑战第3天】本文介绍了在Java环境中构建RESTful API的重要性及方法。遵循REST原则,利用HTTP方法处理资源,实现CRUD操作。在Java中,常用框架如Spring MVC简化了RESTful服务开发,包括定义资源、设计表示层、实现CRUD、考虑安全性、文档和测试。通过Spring MVC示例展示了创建RESTful服务的步骤,强调了其在现代Web服务开发中的关键角色,有助于提升互操作性和用户体验。
构建RESTful API:Java中的RESTful服务开发
|
20天前
|
XML JSON 安全
谈谈你对RESTful API设计的理解和实践。
RESTful API是基于HTTP协议的接口设计,通过URI标识资源,利用GET、POST、PUT、DELETE等方法操作资源。设计注重无状态、一致性、分层、错误处理、版本控制、文档、安全和测试,确保易用、可扩展和安全。例如,`/users/{id}`用于用户管理,使用JSON或XML交换数据,提升系统互操作性和可维护性。
14 4
|
22天前
|
安全 API 开发者
构建高效可扩展的RESTful API服务
在数字化转型的浪潮中,构建一个高效、可扩展且易于维护的后端API服务是企业竞争力的关键。本文将深入探讨如何利用现代后端技术栈实现RESTful API服务的优化,包括代码结构设计、性能调优、安全性强化以及微服务架构的应用。我们将通过实践案例分析,揭示后端开发的最佳实践,帮助开发者提升系统的响应速度和处理能力,同时确保服务的高可用性和安全。
25 3
|
29天前
|
缓存 前端开发 API
构建高效可扩展的RESTful API:后端开发的最佳实践
【2月更文挑战第30天】 在现代Web应用和服务端架构中,RESTful API已成为连接前端与后端、实现服务间通信的重要接口。本文将探讨构建一个高效且可扩展的RESTful API的关键步骤和最佳实践,包括设计原则、性能优化、安全性考虑以及错误处理机制。通过这些实践,开发者可以确保API的健壮性、易用性和未来的可维护性。
|
30天前
|
API 开发者 UED
深入探讨RESTful API设计原则及最佳实践
在当今互联网时代,RESTful API已成为各种软件系统之间进行通信的重要方式。本文将从资源定义、URI设计、HTTP方法选择、状态码规范等方面深入探讨RESTful API设计的原则与最佳实践,帮助开发者更好地构建高效、健壮的API。
|
10天前
|
Go
go语言中的数据类型
go语言中的数据类型
11 0
|
16天前
|
Go 开发者
掌握Go语言:Go语言结构体,精准封装数据,高效管理实体对象(22)
掌握Go语言:Go语言结构体,精准封装数据,高效管理实体对象(22)
|
16天前
|
安全 Go
掌握Go语言:Go语言通道,并发编程的利器与应用实例(20)
掌握Go语言:Go语言通道,并发编程的利器与应用实例(20)