目录
一、JWT详细介绍
1.JWT组成
JWT是一种轻量级的身份验证和授权机制,全称为JSON Web Token。它由三部分组成,分别是Header、Payload和Signature。
-
Header:JWT头部通常由两部分组成,第一部分是声明类型,例如JWT,第二部分是声明所使用的算法,例如HMAC SHA256或者RSA等。
-
Payload:Payload是JWT的第二部分,它包含了具体的用户信息,例如用户ID、用户名、角色等,也可以包含自定义的其他信息。Payload中的数据是以JSON格式进行编码,并且经过Base64URL编码。
-
Signature:Signature是JWT的第三部分,它使用Header和Payload中的数据以及一个密钥来生成签名。签名的目的是保证消息没有被篡改,并且只能被服务器端识别和验证。
使用JWT进行身份验证和授权时,客户端在登录认证成功后会将JWT作为一个字符串返回给客户端,客户端之后每次请求都需要在HTTP头部中带上这个JWT字符串以进行身份验证和权限验证。因为JWT中已经包含有用户信息和签名,服务器端不需要再查询数据库或者其它存储来获取用户信息。
2.JWT的优点
-
去中心化验证:因为JWT本身已经包含了用户信息和签名,服务端不需要维护任何状态信息,从而实现去中心化验证。
-
跨语言支持:由于JWT是基于标准的JSON格式和Base64URL编码实现的,因此它可以在不同的平台和语言之间进行传输和解析。
-
安全性:在生成JWT签名时使用了加密算法,保证了JWT数据的安全性和完整性。
总之,JWT是一种简单、安全、便捷的身份验证和授权机制,在现代Web应用程序中得到广泛应用。
二、JWT使用示例
当用户使用登录凭证进行身份验证时,服务器通过生成一个JWT并将其发送给客户端完成身份验证的过程。
首先需要引入相关依赖:
<!-- Spring Security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- JWT -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
然后定义一个JWT工具类,用于生成和解析JWT:
@Service
public class JwtUtils {
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private long expiration;
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
claims.put("sub", userDetails.getUsername());
claims.put("iat", new Date());
claims.put("exp", new Date(System.currentTimeMillis() + expiration * 1000));
return Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS512, secret).compact();
}
public String getUsernameFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getSubject();
}
public boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return username.equals(userDetails.getUsername()) && !isTokenExpired(token);
}
private boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}
private Date getExpirationDateFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().getExpiration();
}
}
这里使用了Spring Security框架提供的UserDetails接口来表示用户信息,通过JwtUtils.generateToken()方法生成JWT字符串,并使用JwtUtils.getUsernameFromToken()方法从JWT中解析出用户名。validateToken()方法用于验证JWT是否合法,isTokenExpired()方法用于判断JWT是否过期。
最后,在登录成功后可以将JWT发送给客户端:
@RestController
public class LoginController {
@Autowired
private JwtUtils jwtUtils;
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
// 验证用户身份
UserDetails userDetails = userDetailsService.loadUserByUsername(loginRequest.getUsername());
if (passwordEncoder.matches(loginRequest.getPassword(), userDetails.getPassword())) {
// 生成JWT
String token = jwtUtils.generateToken(userDetails);
Map<String, Object> response = new HashMap<>();
response.put("token", token);
return ResponseEntity.ok(response);
} else {
throw new BadCredentialsException(" 验证失败,账号或密码不存在.");
}
}
}
在登录成功后,通过JwtUtils.generateToken()方法生成JWT,并将其封装在响应中返回给客户端。