JWT(JSON Web Token)是一种用于安全地在用户和服务器之间传递信息的机制,常用于身份验证和信息交换。
JWT的工作流程
- 用户登录:用户输入凭证(如用户名和密码)并发送给服务器。
- 服务器验证:服务器验证凭证的有效性。
- 生成JWT:如果凭证有效,服务器生成JWT,并将其返回给客户端。
- 客户端存储:客户端存储JWT(通常存储在localStorage或sessionStorage中)。
- 后续请求:客户端在后续请求中将JWT放在HTTP头中(通常是
Authorization: Bearer <token>)。 - 服务器验证JWT:服务器接收请求,验证JWT的有效性,并根据JWT中的信息执行相应的操作。
- 过期时间:JWT通常会设置过期时间(
exp),确保令牌在一定时间后失效。 - 密钥管理:确保密钥的安全性,避免泄露。
- HTTPS:始终使用HTTPS来传输JWT,以防止中间人攻击。
JWT 登录验证实现详细步骤
1. 添加依赖
首先,你需要在你的项目中添加JWT的相关依赖。以Maven为例,打开pom.xml并添加以下依赖:
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2. 创建JWT工具类
创建一个工具类来处理JWT的生成和验证。
JwtUtil.java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class JwtUtil {
private static final String SECRET_KEY = "your_secret_key"; // 替换为你的密钥
private static final long EXPIRATION_TIME = 86400000; // 24小时
// 生成JWT
public static String generateToken(String username) {
Map<String, Object> claims = new HashMap<>();
claims.put("username", username);
JwtBuilder builder = Jwts.builder()
.setClaims(claims)
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SECRET_KEY);
return builder.compact();
}
// 验证JWT
public static Claims validateToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
}
3. 实现用户登录
在Controller层实现用户登录逻辑,验证用户身份并生成JWT。
AuthController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/auth")
public class AuthController {
@Autowired
private UserService userService;
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody LoginRequest loginRequest) {
// 验证用户身份
User user = userService.authenticate(loginRequest.getUsername(), loginRequest.getPassword());
if (user != null) {
// 生成JWT
String token = JwtUtil.generateToken(user.getUsername());
return ResponseEntity.ok(token);
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
}
}
}
4. 添加JWT过滤器
创建一个过滤器,用于拦截请求并验证JWT。
JwtRequestFilter.java
import io.jsonwebtoken.Claims;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
// 从请求头中获取JWT
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
Claims claims = JwtUtil.validateToken(jwt);
username = claims.getSubject();
}
// 设置用户信息到SecurityContext(如果需要的话)
if (username != null) {
// 可以在这里设置用户的权限等信息
}
chain.doFilter(request, response);
}
}
5. 配置Spring Security
在Spring Security配置中添加JWT过滤器以保护需要身份验证的路由。
SecurityConfig.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() // 禁用CSRF保护
.authorizeRequests()
.antMatchers("/api/auth/login").permitAll() // 允许登录请求
.anyRequest().authenticated(); // 其他请求需要身份验证
// 添加JWT过滤器
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
6. 用户服务实现
实现用户验证逻辑的服务类。
UserService.java
import org.springframework.stereotype.Service;
@Service
public class UserService {
public User authenticate(String username, String password) {
// 这里可以调用数据库查询用户并验证密码
// 这是一个简单示例,实际应用中应加密密码并进行安全检查
if ("user".equals(username) && "password".equals(password)) {
return new User(username); // 返回用户对象
}
return null; // 身份验证失败
}
}
7. 用户类和请求类
定义用户类和登录请求类。
User.java
public class User {
private String username;
public User(String username) {
this.username = username;
}
public String getUsername() {
return username;
}
}
LoginRequest.java
public class LoginRequest {
private String username;
private String password;
// Getter和Setter
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
总结
以上是使用JWT实现登录验证的完整步骤。主要步骤包括:
- 添加依赖:引入JWT库。
- 创建JWT工具类:生成和验证JWT。
- 实现用户登录:在Controller中处理登录请求,生成JWT。
- 添加JWT过滤器:拦截请求并验证JWT。
- 配置Spring Security:保护需要身份验证的路由。
- 实现用户服务:验证用户身份。
- 定义用户类和请求类:用于处理用户信息和登录请求。