filterChain.doFilter 未在 Spring 内到达目的地
filterChain.doFilter does not reach its destination in Spring
我有以下基于请求正文创建用户的控制器。
@PostMapping
public void registerNewUser(@RequestBody User user) {
userService.addNewUser(user);
}
不过,我还实现了一个过滤器链来验证请求的 cookie,但由于我正在创建用户,因此不需要验证 cookie。因此我做了以下 if 语句
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if(request.getCookies() == null) {
filterChain.doFilter(request, response);
return;
}
....
但这就是问题所在。它没有到达其最终目的地(控制器)并创建我的用户。事实上,它给了我一个 403 Forbidden 状态代码。
我错过了什么?
我怀疑是我的身份验证过滤器导致了这个问题。我相信它正在尝试验证我不想用于注册端点的所有传入请求。
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
UsernameAndPasswordAuthenticationRequest authenticationRequest = new ObjectMapper().readValue(request.getInputStream(), UsernameAndPasswordAuthenticationRequest.class);
Authentication authentication = new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword());
Authentication authenticate = authenticationManager.authenticate(authentication);
return authenticate;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
String token = Jwts.builder()
.setSubject(authResult.getName())
.claim("authorities", authResult.getAuthorities())
.setIssuedAt(new Date())
.setExpiration(java.sql.Date.valueOf(LocalDate.now().plusDays(jwtConfig.getTokenExpirationAfterDays())))
.signWith(secretKey)
.compact();
response.resetBuffer();
response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
response.getOutputStream().print(new ObjectMapper().writeValueAsString("Authenticated!"));
Cookie sessionCookie = new Cookie("JSESSIONID", token);
response.addCookie(sessionCookie);
response.flushBuffer();
}
}
我的配置
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(corsConfigurationSource()).and().csrf().disable().formLogin().disable().httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
.addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig), JwtUsernameAndPasswordAuthenticationFilter.class)
.authorizeRequests().antMatchers("/", "index", "/css/*", "/js/*").permitAll().antMatchers("/api/**")
.hasRole(ApplicationUserRole.USER.name()).anyRequest().authenticated();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("GET","POST", "OPTIONS", "PUT", "DELETE"));
configuration.addAllowedHeader("Access-Control-Allow-Origin");
configuration.addAllowedHeader("Content-Type");
configuration.setAllowCredentials(true);
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(applicationUserService);
return provider;
}
@Configuration
@EnableWebMvc
public class CorsConfig implements WebMvcConfigurer{
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000").allowCredentials(true).allowedMethods("GET", "POST","PUT", "DELETE", "OPTIONS");
}
};
}
}
刚刚更新:
我已经实现了一个shouldnotfilter方法来避免在注册时被过滤,但问题仍然存在。我仍然收到 403 Forbidden,但它似乎没有在注册端点上进行过滤
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String path = request.getRequestURI();
return "/management/api/v1/users/register".equals(path);
}
所以问题实际上是在配置方法中。我实际上只允许特定端点 role-specific 用户如下:
.antMatchers("/api/**") .hasRole(ApplicationUserRole.USER.name()).anyRequest().authenticated()
我错过了这个,因为我实际上在使用 /management/api/ 但不知道这个被应用了,以为我的过滤器有问题,但这是一个安全配置问题。
我有以下基于请求正文创建用户的控制器。
@PostMapping
public void registerNewUser(@RequestBody User user) {
userService.addNewUser(user);
}
不过,我还实现了一个过滤器链来验证请求的 cookie,但由于我正在创建用户,因此不需要验证 cookie。因此我做了以下 if 语句
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if(request.getCookies() == null) {
filterChain.doFilter(request, response);
return;
}
....
但这就是问题所在。它没有到达其最终目的地(控制器)并创建我的用户。事实上,它给了我一个 403 Forbidden 状态代码。 我错过了什么?
我怀疑是我的身份验证过滤器导致了这个问题。我相信它正在尝试验证我不想用于注册端点的所有传入请求。
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
UsernameAndPasswordAuthenticationRequest authenticationRequest = new ObjectMapper().readValue(request.getInputStream(), UsernameAndPasswordAuthenticationRequest.class);
Authentication authentication = new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword());
Authentication authenticate = authenticationManager.authenticate(authentication);
return authenticate;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
String token = Jwts.builder()
.setSubject(authResult.getName())
.claim("authorities", authResult.getAuthorities())
.setIssuedAt(new Date())
.setExpiration(java.sql.Date.valueOf(LocalDate.now().plusDays(jwtConfig.getTokenExpirationAfterDays())))
.signWith(secretKey)
.compact();
response.resetBuffer();
response.setHeader(HttpHeaders.CONTENT_TYPE, "application/json");
response.getOutputStream().print(new ObjectMapper().writeValueAsString("Authenticated!"));
Cookie sessionCookie = new Cookie("JSESSIONID", token);
response.addCookie(sessionCookie);
response.flushBuffer();
}
}
我的配置
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(corsConfigurationSource()).and().csrf().disable().formLogin().disable().httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig, secretKey))
.addFilterAfter(new JwtTokenVerifier(secretKey, jwtConfig), JwtUsernameAndPasswordAuthenticationFilter.class)
.authorizeRequests().antMatchers("/", "index", "/css/*", "/js/*").permitAll().antMatchers("/api/**")
.hasRole(ApplicationUserRole.USER.name()).anyRequest().authenticated();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(daoAuthenticationProvider());
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
configuration.setAllowedMethods(Arrays.asList("GET","POST", "OPTIONS", "PUT", "DELETE"));
configuration.addAllowedHeader("Access-Control-Allow-Origin");
configuration.addAllowedHeader("Content-Type");
configuration.setAllowCredentials(true);
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder);
provider.setUserDetailsService(applicationUserService);
return provider;
}
@Configuration
@EnableWebMvc
public class CorsConfig implements WebMvcConfigurer{
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("http://localhost:3000").allowCredentials(true).allowedMethods("GET", "POST","PUT", "DELETE", "OPTIONS");
}
};
}
}
刚刚更新:
我已经实现了一个shouldnotfilter方法来避免在注册时被过滤,但问题仍然存在。我仍然收到 403 Forbidden,但它似乎没有在注册端点上进行过滤
@Override
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
String path = request.getRequestURI();
return "/management/api/v1/users/register".equals(path);
}
所以问题实际上是在配置方法中。我实际上只允许特定端点 role-specific 用户如下:
.antMatchers("/api/**") .hasRole(ApplicationUserRole.USER.name()).anyRequest().authenticated()
我错过了这个,因为我实际上在使用 /management/api/ 但不知道这个被应用了,以为我的过滤器有问题,但这是一个安全配置问题。