我正在基于一些开源项目和网上发现的一些文档,开发一个带有Spring引导的JWT实现。
什么有效? 我能够生成我的令牌,当我尝试调用一些安全的方法时,在第一次打击时我被撤销了,这很好。
有什么问题? 一旦我生成令牌,似乎我可以调用我的安全方法而无需添加我的Authorization标头。
我正在调试我的代码并发现我在SecurityContextHolder中设置了身份验证,但是在请求完成后我不会清空此变量。在每个实现中发现没有人这样做,所以我的问题是我是否必须这样做以使我的代码按照假设工作,只有当有一个带有有效令牌的授权头时检索安全路径?
我的代码:
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;
}
}
这是我的控制器测试类
@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";
}
}
谢谢
答案 0 :(得分:0)
所以我的问题的答案需要两个修改:
.sessionManagement()。sessionCreationPolicy(SessionCreationPolicy.STATELESS)
if(username!= null&amp;&amp; SecurityContextHolder.getContext()。getAuthentication()== null)