gpt4 book ai didi

java - 使用 JWT 完成请求后是否必须清空 SecurityContextHolder

转载 作者:太空宇宙 更新时间:2023-11-04 11:20:13 26 4
gpt4 key购买 nike

我正在基于一些开源项目和网上找到的一些文档,使用 Spring boot 来实现 JWT。

什么在起作用?我能够生成我的 token ,并且在第一次点击时,当我尝试调用一些安全方法时,我被撤销,这很好。

有什么问题吗?生成 token 后,似乎我可以调用我的安全方法,而无需添加我的授权 header 。

我正在调试我的代码,发现我在 SecurityContextHolder 中设置了身份验证,但请求完成后我不会清空此变量。在每个实现中都没有人这样做,所以我的问题是我是否必须这样做才能让我的代码按预期工作,仅在存在带有有效 token 的授权 header 时检索安全路径?

我的代码:

WebSecurityConfig 类:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserSecurityService userSecurityService;


@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/public").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();

// And filter other requests to check the presence of JWT in header
http.addFilterBefore(jwtAuthenticationFilterBean(),
UsernamePasswordAuthenticationFilter.class);

// Disable page caching
http.headers().cacheControl();
}

@Bean
public JWTAuthenticationFilter jwtAuthenticationFilterBean() {
return new JWTAuthenticationFilter();
}

@Override
protected void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userSecurityService);
}
}

JWTAuthenticationFiler 类

public class JWTAuthenticationFilter extends OncePerRequestFilter {


@Autowired
private UserDetailsService userDetailsService;

@Value("${jwt.token.header}")
private String tokenHeader;

@Autowired
TokenAuthenticationService tokenAuthenticationService;


@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
String token = httpServletRequest.getHeader(tokenHeader);

String username = tokenAuthenticationService.getUsernameFromToken(token);

if(username != null && SecurityContextHolder.getContext().getAuthentication() != null){
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (tokenAuthenticationService.validateToken(token, userDetails)) {
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
}
}

filterChain.doFilter(httpServletRequest, httpServletResponse);

}

}

TokenAuthenticationService 类

@Service
public class TokenAuthenticationService implements Serializable {

static final String CLAIM_KEY_USERNAME = "sub";
static final String CLAIM_KEY_AUDIENCE = "audience";
static final String CLAIM_KEY_CREATED = "created";
static final String CLAIM_KEY_EXPIRED = "exp";

static final long EXPIRATIONTIME = 864_000_000; // 10 days
static final String SECRET = "ThisIsASecret";
static final String TOKEN_PREFIX = "Bearer";
static final String HEADER_STRING = "Authorization";

@Value("${jwt.token.expiration}")
private Long expiration;

@Value("${jwt.token.secret}")
private String secret;

public String generateToken(UserDetails user) {

Map<String, Object> claims = new HashMap<>();

claims.put(CLAIM_KEY_USERNAME, user.getUsername());

final Date createdDate = new Date();
claims.put(CLAIM_KEY_CREATED, createdDate);

final Date expirationDate = new Date(createdDate.getTime() + expiration * 1000);

return Jwts.builder()
.setClaims(claims)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}

public String getUsernameFromToken(String token) {
String username;
try{
final Claims claims = getClaimsFromToken(token);
username = claims.getSubject();
}catch (Exception e){
username = null;
}
return username;
}

private Claims getClaimsFromToken(String token) {
Claims claims;
try {
claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}catch (Exception e){
claims = null;
}
return claims;
}

public boolean validateToken(String token, UserDetails userDetails) {

final String username = getUsernameFromToken(token);
final Date created = getCreatedDateFromToken(token);

if(userDetails.getUsername().equals(username) && !isTokenExpired(token)){
return true;
}
return false;
}

private boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}

private Date getExpirationDateFromToken(String token) {
Date expiration;
try {
final Claims claims = getClaimsFromToken(token);
expiration = claims.getExpiration();
}catch (Exception e){
expiration = null;
}
return expiration;
}

private Date getCreatedDateFromToken(String token) {
Date createdDate;
try{
final Claims claims = getClaimsFromToken(token);
createdDate = new Date((Long) claims.get(CLAIM_KEY_CREATED));
}catch (Exception e){
createdDate = null;
}
return createdDate;

}
}

这是我的 Controller 测试类

@RestController
public class TestController {

@GetMapping("/public")
public String testPublic(){
return "Welcom to the public place";
}

@GetMapping("/private")
@PreAuthorize("hasRole('USER')")
public String testPrivate(){
return "Welcome to the private place";
}

@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public String testAdmin(){
return "Welcome to the admin place";
}

}

谢谢

最佳答案

所以我的问题的答案需要进行两处修改:

  1. 我们需要将其添加到我们的 WebSecurityConfig 中来拥有无状态 session 管理策略

.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)

  • 第二件事是我的代码中的拼写错误,我们必须确保在过滤器的条件下身份验证为空:
  • if(username != null && SecurityContextHolder.getContext().getAuthentication() == null)

    关于java - 使用 JWT 完成请求后是否必须清空 SecurityContextHolder,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45001060/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com