温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

SpringBootSecurity中JWT的使用方法

发布时间:2021-09-28 09:44:08 来源:亿速云 阅读:161 作者:柒染 栏目:大数据
# 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> 

2.2 JWT工具类实现

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(); } } 

三、Spring Security配置

3.1 安全配置类

@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); } } 

3.2 JWT认证过滤器

@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); } } 

四、实现认证接口

4.1 认证控制器

@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); } } } 

4.2 DTO对象

public class JwtRequest implements Serializable { private String username; private String password; // getters & setters } public class JwtResponse implements Serializable { private final String token; // constructor & getter } 

五、测试与验证

5.1 测试流程

  1. 发送POST请求到/authenticate获取token
curl -X POST \ http://localhost:8080/authenticate \ -H 'Content-Type: application/json' \ -d '{"username":"admin","password":"password"}' 
  1. 使用返回的token访问受保护接口
curl -X GET \ http://localhost:8080/api/protected \ -H 'Authorization: Bearer <token>' 

5.2 常见问题排查

  1. Token过期:检查token有效期设置
  2. 签名不匹配:确保服务端和客户端的secret key一致
  3. 跨域问题:配置CORS过滤器
  4. 权限不足:检查用户角色和接口权限配置

六、进阶优化

6.1 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"); } 

6.2 黑名单机制

实现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); } } 

6.3 分布式系统支持

在微服务架构中: 1. 使用统一的认证服务 2. 配置相同的secret key 3. 考虑使用JWT + OAuth2组合方案

七、安全注意事项

  1. Secret Key保护:不要硬编码在代码中,使用环境变量或配置中心
  2. HTTPS:生产环境必须启用HTTPS
  3. Token有效期:设置合理的过期时间(建议2-4小时)
  4. 敏感数据:不要在payload中存放敏感信息
  5. 注销处理:实现短有效期+黑名单机制

结语

本文详细介绍了在Spring Boot Security中集成JWT的完整方案,从基础概念到具体实现,涵盖了认证流程、安全配置、接口开发和进阶优化等内容。JWT为现代分布式系统提供了轻量级的安全解决方案,结合Spring Security可以构建出既安全又灵活的认证授权体系。

实际项目中,开发者还需要根据具体业务需求进行调整,比如添加多因素认证、审计日志等功能,以构建更加完善的安保系统。 “`

注:本文实际字数为约3200字,包含了完整的代码实现和理论说明。如需调整内容或字数,可以进一步修改补充。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI