用户token鉴权的学习和代码实现思路 | 青训营

635 阅读5分钟

认真阅读了一下官方提供的API定义文档,发现绝大多数的API请求都必需带上用户鉴权token,是一个非常重要的功能。

学习了一下Token鉴权的概念,并且成功在大项目的开发中应用上了。先写一篇伴读笔记记录一下Token的概念和应用场景。

基本概念

令牌(Token)是一种API鉴权的常用方式,尤其是在现代的RESTful服务中。在此背景下,token通常是指JSON Web Token(JWT)或其他类似的结构,但理论上,它可以是任何可以验证用户身份或会话有效性的数据块。

Token的主要作用和特点如下:

  1. 身份验证:Token通常在用户登录后生成并返回给用户。当用户进行后续请求时,他们会将此token发送回服务器,以证明自己的身份。这允许服务器识别并授权该用户。
  2. 状态无关:不同于基于session的鉴权(其中服务器需要跟踪活跃的会话),token-based鉴权是无状态的。每个请求都包含了所有必要的信息,使服务器能够知道请求者是谁并对其进行验证。
  3. 可携带数据:特别是JWT,它可以携带一些数据,如用户ID、角色或其他属性。这使得服务器在不访问数据库的情况下进行某些验证。
  4. 跨域:Token可以用于跨域身份验证,因为它不依赖于基于cookie的会话。
  5. 过期机制:Token可以有一个到期时间。例如,一个token可以被设置为1小时后过期,这会要求用户在1小时后重新登录。
  6. 安全性:Token可以被加密,确保数据的私密性。当使用JWT时,还可以签名以确保数据的完整性。

应用场景举例

在我们的API定义中,用户在登录后会收到一个token。此后,为了访问需要鉴权的端点(如查询用户信息),用户需要将这个token放在请求的Header或者某个特定的参数中发送到服务器。服务器收到请求后,会验证token的有效性(是否被篡改、是否过期等)。只有验证通过的token,对应的请求才会被允许访问受保护的资源。

例如,假设用户登录后收到了一个JWT token。当他们想要查询自己的信息时,他们会发起一个GET请求,并在请求的Authorization头中附带这个token,类似于:

Authorization: Bearer YOUR_JWT_TOKEN

服务器收到请求后,会提取和验证token。如果token有效,服务器会从token中提取用户ID,然后返回与该ID相关的信息。如果token无效或过期,服务器会返回一个错误响应,通常是**401 Unauthorized**。

代码中的实现

因为现在所有队伍都还在开发阶段,就不直接贴代码了,可以记录一下代码实现的思路。

首先我们需要创建两个函数:生成Token和验证Token。

生成Token

这个函数会在用户登录API的函数中被调用,给登录用户生成一个Token。

首先我们定义一个空的claims变量,它是一个jwt.StandardClaims{}类型,来自github.com/golang-jwt/…库。

Claims

这里需要解释一下Claims这个概念。它是一个JSON对象,包含了我们发送请求所需要的声明信息,其中包含了我们的请求主体和额外的元数据。

jwt.StandardClaims结构体的定义是:

type StandardClaims struct {
    Audience  string `json:"aud,omitempty"`
    ExpiresAt int64  `json:"exp,omitempty"`
    Id        string `json:"jti,omitempty"`
    IssuedAt  int64  `json:"iat,omitempty"`
    Issuer    string `json:"iss,omitempty"`
    NotBefore int64  `json:"nbf,omitempty"`
    Subject   string `json:"sub,omitempty"`
}

他们的含义是:

  • Audience (aud) : JWT 的受众,通常是用户的 ID。
  • ExpiresAt (exp) : 代表什么时候 token 会过期。这是一个 Unix 时间戳。
  • Id (jti) : token 的唯一身份标识。
  • IssuedAt (iat) : 代表这个 JWT 何时被创建。
  • Issuer (iss) : JWT 的发行者。
  • **NotBefore (nbf)**: 定义在某个时间之前,该 JWT 不应被接受。
  • Subject (sub) : JWT 的主题。

我们的代码中只需要用到ExpiresAtId

我们将用户ID和到期时间(比如现在开始24小时)填充给claims。

然后用jwt.NewWithClaims方法将我们的claims生成一个Token,然后再用一个事先定义好的秘钥(secret key)对Token签名,就生成了我们要返回给用户的Token了。

解析和验证Token

这个方法将在所有需要验证用户Token的API函数中被调用。它接收一个Token,然后解析验证这个Token,最后返回用户Id。相当于是生成Token函数的反向过程。

验证Token中间件

当我们定义好解析验证Token的函数后,我们可以写一个中间件函数Authentication(),它的作用是在所有需要Token鉴权的API工作之前,先验证Token的有效性,如果无效,那么我们就不执行API函数(通过c.Abort())。API函数接到通知说验证不通过的话,就直接返回一个HTTP 401 Unauthorized

注册中间件

最后我们将Authentication()函数注册在所有需要用户token鉴权的函数上,就可以了。

总结

这篇文章记录学习Token在API鉴权中的应用的一些知识。Token作为一种常见的鉴权方式,具有身份验证、状态无关、可携带数据、跨域、过期机制和安全性等特点。我们还介绍了Token在API请求中的应用场景,以及如何在代码中实现Token的生成和验证,包括Claims的概念、Token签名和解析、验证Token的中间件函数等。