授课语音

JWT 的基本概念与使用场景

JWT(JSON Web Token)是一种轻量级的、跨平台的认证机制。它用于在不同的系统之间传递安全信息,尤其是在基于Web的应用中,广泛应用于用户认证、授权等场景。JWT可以通过加密方式保护数据的完整性和安全性,广泛用于分布式系统中的身份认证。


1. JWT 的基本概念

JWT 是一种用于在网络应用环境间传递声明的 compact 和 URL-safe 的令牌格式。JWT 由三部分组成:

  1. 头部(Header):通常包含令牌的类型(JWT)和签名算法(如HMAC SHA256或者RSA)。
  2. 载荷(Payload):包含声明信息(Claims)。JWT的载荷部分是可自定义的,可以包含用户身份、权限等信息。
  3. 签名(Signature):由头部和载荷部分以及密钥生成,确保JWT的完整性和认证来源。

JWT格式:

Header.Payload.Signature

JWT 的结构图:

  1. Header:用于声明令牌的类型(通常为JWT)和签名算法(如HMAC SHA256,RSA等)。
  2. Payload:包含了需要传输的数据(声明)。这些声明是以键值对的形式存储的,可以是公认的注册声明、私有声明等。
  3. Signature:通过头部指定的算法对头部和载荷进行签名,确保数据的完整性和认证来源。

2. JWT 的使用场景

JWT在现代Web应用中非常常见,主要用于身份验证和授权。以下是JWT的几个典型应用场景:

2.1 用户认证

当用户登录时,系统会验证其身份并生成一个JWT令牌,令牌中包含用户信息和权限。随后用户每次发送请求时都需要携带这个JWT,以证明自己的身份。

  • 优点:无需频繁查询数据库或会话存储,提高系统性能。
  • 常见应用:登录认证,OAuth2.0认证,单点登录(SSO)等。

2.2 用户授权

JWT可以包含用户的角色和权限信息。在分布式应用中,服务端可以通过解析JWT来验证用户是否有权限执行某些操作。例如,可以在JWT中添加“角色(role)”字段来进行权限管理。

  • 优点:可以实现灵活的权限控制,适用于微服务架构中的跨服务权限验证。
  • 常见应用:API的权限控制,微服务之间的身份和权限验证等。

2.3 单点登录(SSO)

JWT广泛应用于单点登录(SSO)系统中。在多个服务之间共享用户的认证信息时,使用JWT可以避免在每个服务中都存储用户的认证状态。用户登录后,JWT作为全局认证令牌传递给各个子系统。

  • 优点:实现跨多个系统的统一认证,提升用户体验。
  • 常见应用:企业内部多个系统的统一登录,第三方授权(如Google、GitHub登录)等。

3. JWT 的工作原理

JWT在认证和授权中通常遵循以下流程:

  1. 用户登录: 用户提交用户名和密码,后端服务器验证用户身份。

  2. 生成JWT: 一旦用户验证通过,后端生成一个JWT,包含用户信息(如ID、角色等)和有效期。服务器使用密钥对JWT进行签名。

  3. 返回JWT: 后端将JWT返回给客户端,客户端将其存储(通常在浏览器的localStorage或sessionStorage中)。

  4. 发送请求时携带JWT: 客户端在每次请求时,将JWT作为HTTP请求头(Authorization)的一部分发送给后端。

  5. 验证JWT: 后端接收到JWT后,使用密钥对其进行验证,确认JWT没有被篡改,并检查其有效期。

  6. 授权操作: 如果JWT有效且权限足够,后端允许客户端执行相应的操作;否则,返回错误信息。


4. JWT 代码实现

4.1 安装依赖

首先,使用Go语言的JWT库来生成和解析JWT。常用的Go语言JWT库是github.com/dgrijalva/jwt-go

go get github.com/dgrijalva/jwt-go

4.2 生成 JWT

以下是一个使用Go生成JWT的示例代码:

package main

import (
	"fmt"
	"time"
	"github.com/dgrijalva/jwt-go"
)

// 定义密钥
var mySigningKey = []byte("secret")

// 定义JWT的Claims
type MyClaims struct {
	Username string `json:"username"`
	jwt.StandardClaims
}

func generateJWT(username string) (string, error) {
	// 设置JWT的有效载荷
	claims := MyClaims{
		Username: username,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: time.Now().Add(time.Hour * 72).Unix(), // 设置过期时间为72小时
			Issuer:    "my-app", // 设置发行者
		},
	}

	// 使用HMAC签名算法生成token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

	// 生成token字符串
	tokenString, err := token.SignedString(mySigningKey)
	if err != nil {
		return "", err
	}

	return tokenString, nil
}

func main() {
	// 生成JWT
	tokenString, err := generateJWT("john_doe")
	if err != nil {
		fmt.Println("生成JWT失败:", err)
		return
	}
	fmt.Println("生成的JWT:", tokenString)
}

4.3 解析 JWT

当用户每次请求时,后端可以使用密钥解析JWT并验证其有效性。以下是解析JWT的代码示例:

package main

import (
	"fmt"
	"github.com/dgrijalva/jwt-go"
	"strings"
)

// 定义密钥
var mySigningKey = []byte("secret")

func parseJWT(tokenString string) (*jwt.Token, error) {
	// 解析JWT并验证
	token, err := jwt.ParseWithClaims(tokenString, &MyClaims{}, func(token *jwt.Token) (interface{}, error) {
		// 确保token签名方法是HMAC
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("签名方法不匹配")
		}
		return mySigningKey, nil
	})
	if err != nil {
		return nil, err
	}
	return token, nil
}

func main() {
	// 假设接收到的JWT
	tokenString := "<your-jwt-token-here>"

	// 解析JWT
	token, err := parseJWT(tokenString)
	if err != nil {
		fmt.Println("解析JWT失败:", err)
		return
	}

	// 获取JWT中的Claim数据
	if claims, ok := token.Claims.(*MyClaims); ok && token.Valid {
		fmt.Println("Username:", claims.Username)
	} else {
		fmt.Println("无效的JWT")
	}
}

4.4 代码解析

  1. 生成JWT

    • 使用jwt.NewWithClaims创建一个新的JWT,并指定SigningMethodHS256作为签名算法。
    • 设置JWT的有效期(72小时)和发行者信息。
    • 使用SignedString方法签名JWT,生成最终的JWT字符串。
  2. 解析JWT

    • 使用jwt.ParseWithClaims方法解析JWT,提供一个验证函数来检查签名是否有效。
    • 如果JWT有效,可以通过token.Claims获取JWT中的用户信息。

5. 总结

通过本课的学习,我们了解了JWT的基本概念、使用场景及其工作原理。JWT广泛应用于用户认证、授权和单点登录等场景。通过Go语言的jwt-go库,我们能够方便地生成和解析JWT,实现安全可靠的用户身份验证与权限控制。在实际开发中,JWT为我们提供了一个简洁高效的认证解决方案,适用于分布式系统和微服务架构中的身份验证需求。

去1:1私密咨询

系列课程: