使用 Spring Security 和 JWT 实现安全认证机制
在现代 Web 应用中,安全认证和授权是保障数据安全和用户隐私的核心机制。Spring Security 是 Spring 框架下专为安全设计的模块,具有高度的可配置性和扩展性。而 JWT(JSON Web Token) 则是当前流行的认证解决方案,因其无状态、可扩展性强等特点被广泛应用于微服务和移动应用中。
本文将从以下几个部分详细介绍如何使用 Spring Security 和 JWT 实现一个完整的认证机制:
- JWT 认证流程概述
- Spring Security 的基本配置
- JWT 生成与解析
- 基于 Spring Security 的 JWT 安全配置
- 实现用户登录和认证
1. JWT 认证流程概述
JWT 的认证流程如下:
- 用户登录:用户通过用户名和密码发送请求给服务器。
- 服务器验证:服务器验证用户身份,验证通过后生成 JWT Token。
- Token 下发:服务器将生成的 Token 返回给客户端。
- 后续请求携带 Token:客户端在后续请求中将 JWT Token 添加到请求头中,服务器通过解析和验证 Token 确认请求的合法性。
这种方式的核心优势在于 Token 是无状态的,服务器无需维护用户的会话信息,且 JWT 可在分布式系统中实现共享认证。
2. Spring Security 的基本配置
创建一个简单的 Spring Boot 项目,并添加 Spring Security 和 JWT 的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
</dependencies>
配置 SecurityConfig 类
创建 SecurityConfig
类以配置 Spring Security 基本设置:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();
}
}
上面的配置指定 /login
接口公开访问,其余接口需要认证后才能访问。
3. JWT 生成与解析
使用 JWT 库生成和解析 Token。创建 JwtUtil
工具类,实现生成和验证 JWT 的方法:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
public class JwtUtil {
private static final String SECRET_KEY = "mySecretKey";
// 生成 JWT
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 24小时有效期
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
// 解析 JWT
public static Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
}
}
4. 基于 Spring Security 的 JWT 安全配置
在 Spring Security 过滤链中添加 JWT 过滤器。实现一个 JwtAuthenticationFilter
类,在每次请求时拦截并验证 Token:
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import io.jsonwebtoken.Claims;
public class JwtAuthenticationFilter extends BasicAuthenticationFilter {
public JwtAuthenticationFilter(AuthenticationManager authManager) {
super(authManager);
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
String token = request.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
chain.doFilter(request, response);
return;
}
Claims claims = JwtUtil.parseToken(token.replace("Bearer ", ""));
String username = claims.getSubject();
if (username != null) {
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>());
SecurityContextHolder.getContext().setAuthentication(auth);
}
chain.doFilter(request, response);
}
}
将 JwtAuthenticationFilter
过滤器添加到 SecurityConfig
中:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()));
}
5. 实现用户登录和认证
创建一个登录控制器 AuthController
,验证用户后生成 JWT:
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
@RestController
public class AuthController {
@PostMapping("/login")
public void login(@RequestParam String username, @RequestParam String password, HttpServletResponse response) {
// 这里简单校验用户名密码
if ("user".equals(username) && "password".equals(password)) {
String token = JwtUtil.generateToken(username);
response.setHeader("Authorization", "Bearer " + token);
} else {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}
}
以上代码实现了一个简单的登录接口,用户登录成功后将返回 JWT Token,并将该 Token 存储在响应头中。
6. 测试与验证
- 获取 Token:使用客户端(例如 Postman)请求
/login
接口,得到包含 JWT Token 的响应头。 - 访问受保护接口:将 Token 添加到请求头
Authorization
中,再次请求受保护接口,验证是否可以成功访问。
结论
通过以上步骤,我们实现了一个基于 Spring Security 和 JWT 的安全认证系统。在实际项目中,可以进一步扩展此功能,例如集成数据库实现用户管理、配置 JWT 自动续签等。这种基于 JWT 的无状态认证适用于分布式系统和微服务架构,有助于提高系统的安全性和可扩展性。