以下是详解JWT token心得与使用实例的完整攻略。
什么是JWT
JWT(JSON Web Token)是一种开放标准,定义了用于在网络应用程序间传递声明的一个紧凑、自包含的方式。JWT 这个标准定义了一种简洁且安全的方式,可以在各方之间传输包含各种信息的 JSON 对象。JWT 主要用于身份验证和授权。
JWT 的组成结构
一个 JWT token 由三部分构成,它们之间通过"."连接,分别是:
- Header(头部)
- Payload(负载)
- Signature(签名)
下面是一个 JWT token 的示例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvbmUgRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
它的三个部分依次是:
Header
Header 部分通常由两部分组成:令牌的类型和使用的签名算法。Header部分通常长这个样子:
{
"alg": "HS256",
"typ": "JWT"
}
其中:
- alg 表示签名算法,这里使用的是 HS256(HMAC with SHA-256)
- typ 是令牌的类型,这里是 JWT
Payload
Payload 部分也是由两部分组成:声明和数据。
声明通常有一些预定义的属性,也允许定义自己的属性。实际应用中,建议使用预定义的属性。
常见的预定义声明有:
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):观众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
一个示例 Payload:
{
"iss": "test",
"exp": 1516239022,
"name": "John Doe",
"admin": true
}
这个 Payload 包括了四个属性:
- iss 表示这个 JWT 的签发者是 test
- exp 表示这个 JWT 在 1516239022 秒之后过期
- name 和 admin 则是自定义的属性
Signature
JWT 的第三部分是 signature ,这个部分将前两部分通过一个特定的算法进行签名生成,然后添加在 JWT 的后面。如果前两部分分别是:header和 payload ,那么使用 key 进行签名的伪代码如下:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
其中,secret 为签名的密钥。
如何使用JWT
要使用 JWT,需要了解如何生成和解析 JWT。
生成 JWT
在 Java 中生成 JWT,我们可以使用io.jsonwebtoken.Jwts
类。以下是一个生成 JWT 的示例:
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class JwtUtils {
private static final long EXPIRATION_TIME = 1000 * 60 * 60 * 24; // 一天的毫秒数
private static final String SIGNATURE_KEY = "mykey"; // TODO: 这里需要替换成自己的密钥
public String generateToken(String username, String role) {
Date now = new Date();
Date expirationDate = new Date(now.getTime() + EXPIRATION_TIME);
return Jwts.builder()
.setSubject(username)
.claim("role", role)
.setIssuedAt(now)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS256, SIGNATURE_KEY)
.compact();
}
}
这个示例中,我们使用 Jwts 类生成了一个 JWT。其中:
- setSubject():表示这个 JWT 的主题,一般是用户的唯一标识符
- claim():表示自定义的声明
- setIssuedAt():表示这个 JWT 的签发时间
- setExpiration():表示这个 JWT 的过期时间
- signWith():表示使用指定的签名算法和密钥对 JWT 进行签名
- compact():表示将 JWT 转换为字符串并返回
解析 JWT
在 Java 中解析 JWT,我们同样可以使用io.jsonwebtoken.Jwts
类。以下是一个解析 JWT 的示例:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
public class JwtUtils {
private static final String SIGNATURE_KEY = "mykey"; // TODO: 这里需要替换成自己的密钥
public void parseToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(SIGNATURE_KEY)
.parseClaimsJws(token)
.getBody();
String username = claims.getSubject();
String role = claims.get("role", String.class);
System.out.println("username: " + username);
System.out.println("role: " + role);
}
}
这个示例中,我们使用 Jwts 类解析了一个 JWT。其中:
- setSigningKey():表示使用指定的密钥对 JWT 进行解密
- parseClaimsJws():表示将 JWT 转换为 Claims 对象
- getSubject():表示获取 JWT 的主题
- get():表示获取自定义的声明
使用示例
以下是两个 JWT 的使用示例。
示例 1
假设我们需要授权一个用户访问一个需要身份验证的 API。以下是一个使用 JWT 的示例:
@RestController
@RequestMapping("/api")
public class ApiController {
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
if ("admin".equalsIgnoreCase(username) && "123456".equals(password)) {
JwtUtils jwtUtils = new JwtUtils();
String token = jwtUtils.generateToken(username, "admin");
return token;
} else {
return "Wrong username/password";
}
}
@GetMapping("/hello")
public String hello(@RequestHeader("Authorization") String authorization) {
if (authorization != null && authorization.startsWith("Bearer ")) {
String token = authorization.substring(7);
JwtUtils jwtUtils = new JwtUtils();
jwtUtils.parseToken(token);
return "Hello!";
} else {
return "Unauthorized";
}
}
}
这个示例中,我们定义了一个需要身份验证的 API /api/hello
,客户端首先需要调用 POST 接口 /api/login
来获取 JWT token。在接下来的调用 /api/hello
接口时,客户端需要在请求头中添加“Bearer ”前缀的 JWT token。服务器将从 JWT token 中获取用户信息并进行身份验证。
示例 2
假设我们需要将一些数据安全地传输给客户端。以下是一个使用 JWT 的示例:
@RestController
@RequestMapping("/api")
public class ApiController {
private static final String SECRET_KEY = "my_secret_key"; // TODO: 这里需要替换成自己的密钥
@GetMapping("/data")
public Map<String, Object> getData() {
Map<String, Object> data = new HashMap<>();
data.put("id", 1);
data.put("name", "John Doe");
JwtUtils jwtUtils = new JwtUtils();
String token = jwtUtils.generateToken(data, SECRET_KEY);
Map<String, Object> result = new HashMap<>();
result.put("token", token);
return result;
}
@GetMapping("/data/{token}")
public Map<String, Object> getData(@PathVariable String token) {
JwtUtils jwtUtils = new JwtUtils();
Map<String, Object> data = jwtUtils.parseToken(token, SECRET_KEY);
return data;
}
}
这个示例中,我们定义了两个接口。在第一个接口 /api/data
中,我们生成一个包含数据的 JWT,并将它作为响应返回给客户端。在第二个接口 /api/data/{token}
中,客户端将 JWT token 作为路径参数发送给服务器,服务器将从 JWT token 中解密数据并返回给客户端。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解JWT token心得与使用实例 - Python技术站