jwt如何进行鉴权用户认证

166 阅读3分钟

JWT已经成为了主流的认证与授权解决方案。它的高效、无状态的特性使得其成为微服务架构中认证和授权的理想选择。JWT 可以在多个系统或服务之间传递身份信息,而不需要为每个请求维护会话信息。JWT 认证的基本流程是:客户端使用用户名和密码登录,服务器生成一个 JWT,并返回给客户端。客户端在后续请求中携带这个 JWT,服务器根据 JWT 来验证用户身份和权限。

JWT组成

一个完整的 JWT 由三部分组成:

  1. Header(头部) :描述 JWT 的元数据,通常包括令牌类型(JWT)和使用的签名算法(如 HMAC SHA256 或 RSA)。 示例:
    {
        "alg": "HS256",
        "typ": "JWT"
    }
    
  2. Payload(有效载荷) :包含声明(Claims),即需要传递的信息。可以是用户的身份信息(如用户 ID)和其他一些数据(如权限、过期时间等)。声明有三种类型: 注册声明(Registered Claims):这些是预定义的声明,例如 iss(发行者)、exp(过期时间)、sub(主题)、aud(受众)等。 公共声明(Public Claims):这些是可以自定义的声明,但是应避免冲突。 私有声明(Private Claims):这些是用于在客户端和服务器之间共享信息的自定义声明。
    {
        "sub": "1234567890",
        "name": "John Doe",
        "iat": 1516239022
    }
    
  3. Signature(签名) :为了防止数据被篡改,JWT 的最后一部分是签名。签名的生成方式是:将编码后的 header 和 payload 用密钥和指定的算法(如 HMAC SHA256RSA)进行签名。
    HMACSHA256(
        base64UrlEncode(header) + "." +
        base64UrlEncode(payload),
        your-256-bit-secret)
    

JWT使用

  • JWT 结构体定义 首先,定义一个 JWT 结构体来封装生成和验证 JWT 所需的关键信息,包括密钥、过期时间、最大刷新时间等。
  • 生成 JWT 通过 NewJWT 方法,我们可以创建一个新的 JWT 实例,用于生成和管理令牌。expireTime 指定了 JWT 的过期时间,maxRefresh 则指定了可以刷新 JWT 的最大时间。
  • 解析 JWT ParseToken 方法用来解析 JWT。它会验证 JWT 是否有效,并解析 JWT 中的声明信息。若 JWT 无效或过期,返回相应的错误。
  • 刷新 JWT 在 JWT 过期后,用户可以通过刷新 JWT 获取新的有效令牌。RefreshToken 方法在最大刷新时间内有效,若超时,则令牌不可再刷新。

JWT 鉴权用户认证流程

1. 用户登录

用户使用用户名和密码向服务器发送登录请求。服务器验证用户信息的正确性,如果成功,则生成 JWT 返回给用户。 示例:

// 伪代码,用户登录并生成 JWT
func login(w http.ResponseWriter, r *http.Request) {
    username := r.FormValue("username")
    password := r.FormValue("password")

    // 验证用户名和密码
    user, err := authenticateUser(username, password)
    if err != nil {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)
        return
    }

    // 创建一个 JWT
    token, err := createJWT(user)
    if err != nil {
        http.Error(w, "Failed to create token", http.StatusInternalServerError)
        return
    }

    // 返回 JWT 给客户端
    w.Header().Set("Authorization", "Bearer "+token)
    w.Write([]byte("Login successful"))
}

在用户成功登录后,服务器生成一个 JWT,并将其返回给客户端。客户端一般会将 JWT 存储在本地的存储中(如 localStoragesessionStorage),并在之后的请求中将 JWT 作为请求头传递。

2. 客户端携带 JWT 发起请求

在客户端发起每个请求时,都会将 JWT 放在请求的 Authorization 头部

// 发送包含 JWT 的请求
req, err := http.NewRequest("GET", "http://localhost:8080/protected", nil)
if err != nil {
    log.Fatal(err)
}
req.Header.Set("Authorization", "Bearer " + token) // JWT token

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
    log.Fatal(err)
}

3. 服务器验证 JWT

服务器在收到请求时,会检查请求头中的 Authorization 字段,提取 JWT,并验证其有效性。验证的主要内容包括:

  • 签名验证:验证 JWT 是否在传输过程中被篡改。
  • 过期时间验证:验证 exp(过期时间)是否有效。
  • 有效载荷验证:根据有效载荷(如用户 ID、角色、权限等)进行权限控制。