您好,登录后才能下订单哦!
密码登录
登录注册
点击 登录注册 即表示同意《亿速云用户服务条款》
# SpringBootSecurity中JWT的使用方法
## 一、JWT基础概念
### 1.1 什么是JWT
JSON Web Token(JWT)是一种开放标准(RFC 7519),用于在各方之间安全地传输信息作为JSON对象。JWT由三部分组成:
- Header(头部)
- Payload(负载)
- Signature(签名)
典型JWT格式:`xxxxx.yyyyy.zzzzz`
### 1.2 JWT的工作流程
1. 客户端通过用户名/密码登录
2. 服务端验证后生成JWT返回
3. 客户端后续请求携带JWT
4. 服务端验证JWT有效性后响应请求
### 1.3 JWT的优势
- 无状态:服务端不需要存储会话信息
- 跨域支持:适合分布式系统和微服务架构
- 安全性:基于数字签名保证数据完整性
## 二、Spring Security集成JWT
### 2.1 环境准备
```xml
<!-- pom.xml 依赖 -->
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
</dependencies>
public class JwtTokenUtil {
private static final String SECRET_KEY = "your-256-bit-secret";
private static final long EXPIRATION_TIME = 864_000_000; // 10天
public static String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return Jwts.builder()
.setClaims(claims)
.setSubject(userDetails.getUsername())
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public static Boolean validateToken(String token, UserDetails userDetails) {
final String username = extractUsername(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}
private static Boolean isTokenExpired(String token) {
return extractExpiration(token).before(new Date());
}
public static String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
private static Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
private static <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private static Claims extractAllClaims(String token) {
return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private UserDetailsService jwtUserDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/authenticate", "/register").permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private JwtUserDetailsService jwtUserDetailsService;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain)
throws ServletException, IOException {
final String requestTokenHeader = request.getHeader("Authorization");
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.extractUsername(jwtToken);
} catch (IllegalArgumentException e) {
logger.error("Unable to get JWT Token");
} catch (ExpiredJwtException e) {
logger.error("JWT Token has expired");
}
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.jwtUserDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}
chain.doFilter(request, response);
}
}
@RestController
public class JwtAuthenticationController {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtTokenUtil jwtTokenUtil;
@Autowired
private JwtUserDetailsService userDetailsService;
@PostMapping("/authenticate")
public ResponseEntity<?> createAuthenticationToken(
@RequestBody JwtRequest authenticationRequest) throws Exception {
authenticate(authenticationRequest.getUsername(),
authenticationRequest.getPassword());
final UserDetails userDetails = userDetailsService
.loadUserByUsername(authenticationRequest.getUsername());
final String token = jwtTokenUtil.generateToken(userDetails);
return ResponseEntity.ok(new JwtResponse(token));
}
private void authenticate(String username, String password) throws Exception {
try {
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(username, password));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED", e);
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS", e);
}
}
}
public class JwtRequest implements Serializable {
private String username;
private String password;
// getters & setters
}
public class JwtResponse implements Serializable {
private final String token;
// constructor & getter
}
/authenticate
获取tokencurl -X POST \
http://localhost:8080/authenticate \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"password"}'
curl -X GET \
http://localhost:8080/api/protected \
-H 'Authorization: Bearer <token>'
@PostMapping("/refresh")
public ResponseEntity<?> refreshToken(HttpServletRequest request) {
String oldToken = request.getHeader("Authorization").substring(7);
if (jwtTokenUtil.canTokenBeRefreshed(oldToken)) {
String newToken = jwtTokenUtil.refreshToken(oldToken);
return ResponseEntity.ok(new JwtResponse(newToken));
}
return ResponseEntity.badRequest().body("Token cannot be refreshed");
}
实现token失效功能:
@Component
public class TokenBlacklist {
private Set<String> blacklist = Collections.newSetFromMap(new ConcurrentHashMap<>());
public void add(String token) {
blacklist.add(token);
}
public boolean contains(String token) {
return blacklist.contains(token);
}
}
在微服务架构中: 1. 使用统一的认证服务 2. 配置相同的secret key 3. 考虑使用JWT + OAuth2组合方案
本文详细介绍了在Spring Boot Security中集成JWT的完整方案,从基础概念到具体实现,涵盖了认证流程、安全配置、接口开发和进阶优化等内容。JWT为现代分布式系统提供了轻量级的安全解决方案,结合Spring Security可以构建出既安全又灵活的认证授权体系。
实际项目中,开发者还需要根据具体业务需求进行调整,比如添加多因素认证、审计日志等功能,以构建更加完善的安保系统。 “`
注:本文实际字数为约3200字,包含了完整的代码实现和理论说明。如需调整内容或字数,可以进一步修改补充。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。