Java Spring Boot REST Api JWT AuthorizationFilter不验证令牌
我制作了一个示例spring boot应用程序,它实现了JWT令牌身份验证,部分工作正常。这意味着在通过使用/login url发送用户详细信息来生成令牌之前,它不允许请求访问端点。一旦接收到令牌,将使用名为Authorization的头发送令牌。因此,直到第一个url全部包含此标头,它才允许访问端点。但是在第一次呼叫之后,我可以在没有包含JWT令牌的授权头的情况下访问enpoints SecurityConfig.javaJava Spring Boot REST Api JWT AuthorizationFilter不验证令牌,java,spring,spring-boot,jwt,Java,Spring,Spring Boot,Jwt,我制作了一个示例spring boot应用程序,它实现了JWT令牌身份验证,部分工作正常。这意味着在通过使用/login url发送用户详细信息来生成令牌之前,它不允许请求访问端点。一旦接收到令牌,将使用名为Authorization的头发送令牌。因此,直到第一个url全部包含此标头,它才允许访问端点。但是在第一次呼叫之后,我可以在没有包含JWT令牌的授权头的情况下访问enpoints SecurityConfig.java @EnableWebSecurity @EnableGlobalMet
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomUserDetailsService customUserDetailsService;
@Autowired
public SecurityConfig(CustomUserDetailsService customUserDetailsService) {
this.customUserDetailsService = customUserDetailsService;
System.out.println("from SecurityConfig constructor");
System.out.println(this.customUserDetailsService.loadUserByUsername("batman").getUsername());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("from configure");
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/sign_up").permitAll()
.antMatchers("/*/floor1/**").hasRole("USER")
.antMatchers("/*/floor2/**").hasRole("ADMIN")
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.addFilter(new JwtAuthorizationFilter(authenticationManager(), customUserDetailsService));
}
}
JwtAuthenticationFilter.java
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
// {"username":"batman","password":"123"}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
System.out.println(">>>>> AuthenticationFilter: checking user credentials....");
ApplicationUser applicationUser = new ObjectMapper().readValue(request.getInputStream(), ApplicationUser.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(applicationUser.getUsername(), applicationUser.getPassword()));
} catch (IOException e) {
System.out.println(">>>>> AuthenticationFilter: error in checking user credentials....");
throw new RuntimeException(e);
} catch (Exception e) {
System.out.println(">>>>> AuthenticationFilter: error in checking user credentials....");
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
System.out.println(">>>>> AuthenticationFilter: successfulAuthentication creating token...");
ZonedDateTime expirationTimeUTC = ZonedDateTime.now(ZoneOffset.UTC).plus(SecurityConstants.EXPIRATION_TIME, ChronoUnit.MILLIS);
String token = Jwts.builder().setSubject(((User)authResult.getPrincipal()).getUsername())
.setExpiration(Date.from(expirationTimeUTC.toInstant()))
.signWith(SignatureAlgorithm.HS256, SecurityConstants.SECRET)
.compact();
response.getWriter().write(token);
response.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
System.out.println(">>>>> AuthenticationFilter: successfulAuthentication token created and added to response");
}
}
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private final CustomUserDetailsService customUserDetailsService;
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, CustomUserDetailsService customUserDetailsService) {
super(authenticationManager);
this.customUserDetailsService = customUserDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String header = request.getHeader(SecurityConstants.HEADER_STRING);
System.out.println(">>>>> AuthorizationFilter doFilterInternal: checking the availability of toke header...");
if(header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)){
System.out.println(">>>>> AuthorizationFilter doFilterInternal: header is null or not start with token prefix");
chain.doFilter(request, response);
return;
}
UsernamePasswordAuthenticationToken authenticationToken = getAuthenticationToken(request);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
chain.doFilter(request, response);
}
private UsernamePasswordAuthenticationToken getAuthenticationToken(HttpServletRequest request){
System.out.println(">>>>> AuthorizationFilter UsernamePasswordAuthentication: validating the token...");
String token = request.getHeader(SecurityConstants.HEADER_STRING);
if(token == null){
System.out.println(">>>>> AuthorizationFilter UsernamePasswordAuthentication: error: token is null");
return null;
}
String username = Jwts.parser().setSigningKey(SecurityConstants.SECRET).parseClaimsJws(token.replace(SecurityConstants.TOKEN_PREFIX, "")).getBody().getSubject();
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
ApplicationUser applicationUser = customUserDetailsService.loadApplicationUserByUsername(username);
return username != null ? new UsernamePasswordAuthenticationToken(applicationUser, null, userDetails.getAuthorities()) : null;
}
}
JwtAuthorizationFilter.java
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
// {"username":"batman","password":"123"}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
System.out.println(">>>>> AuthenticationFilter: checking user credentials....");
ApplicationUser applicationUser = new ObjectMapper().readValue(request.getInputStream(), ApplicationUser.class);
return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(applicationUser.getUsername(), applicationUser.getPassword()));
} catch (IOException e) {
System.out.println(">>>>> AuthenticationFilter: error in checking user credentials....");
throw new RuntimeException(e);
} catch (Exception e) {
System.out.println(">>>>> AuthenticationFilter: error in checking user credentials....");
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
System.out.println(">>>>> AuthenticationFilter: successfulAuthentication creating token...");
ZonedDateTime expirationTimeUTC = ZonedDateTime.now(ZoneOffset.UTC).plus(SecurityConstants.EXPIRATION_TIME, ChronoUnit.MILLIS);
String token = Jwts.builder().setSubject(((User)authResult.getPrincipal()).getUsername())
.setExpiration(Date.from(expirationTimeUTC.toInstant()))
.signWith(SignatureAlgorithm.HS256, SecurityConstants.SECRET)
.compact();
response.getWriter().write(token);
response.addHeader(SecurityConstants.HEADER_STRING, SecurityConstants.TOKEN_PREFIX + token);
System.out.println(">>>>> AuthenticationFilter: successfulAuthentication token created and added to response");
}
}
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private final CustomUserDetailsService customUserDetailsService;
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, CustomUserDetailsService customUserDetailsService) {
super(authenticationManager);
this.customUserDetailsService = customUserDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String header = request.getHeader(SecurityConstants.HEADER_STRING);
System.out.println(">>>>> AuthorizationFilter doFilterInternal: checking the availability of toke header...");
if(header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)){
System.out.println(">>>>> AuthorizationFilter doFilterInternal: header is null or not start with token prefix");
chain.doFilter(request, response);
return;
}
UsernamePasswordAuthenticationToken authenticationToken = getAuthenticationToken(request);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
chain.doFilter(request, response);
}
private UsernamePasswordAuthenticationToken getAuthenticationToken(HttpServletRequest request){
System.out.println(">>>>> AuthorizationFilter UsernamePasswordAuthentication: validating the token...");
String token = request.getHeader(SecurityConstants.HEADER_STRING);
if(token == null){
System.out.println(">>>>> AuthorizationFilter UsernamePasswordAuthentication: error: token is null");
return null;
}
String username = Jwts.parser().setSigningKey(SecurityConstants.SECRET).parseClaimsJws(token.replace(SecurityConstants.TOKEN_PREFIX, "")).getBody().getSubject();
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
ApplicationUser applicationUser = customUserDetailsService.loadApplicationUserByUsername(username);
return username != null ? new UsernamePasswordAuthenticationToken(applicationUser, null, userDetails.getAuthorities()) : null;
}
}
在JwtAuthorizationFilter.java中,如果令牌为check for null,则返回true。因此,应该防止访问端点
并给客户端一个错误。但事实并非如此。它允许请求通过过滤器
并访问端点。如果我遗漏了什么,请帮助我
完整的示例项目:在这里使用两个身份验证过滤器有什么意义?一个是通过验证用户名和密码来验证用户身份。另一个用于验证令牌