尽管有 SecurityConfig,Spring Security 仍会阻止 POST 请求 [英] Spring Security blocks POST requests despite SecurityConfig
问题描述
我正在开发基于 Spring Boot (spring-boot-starter-web
) 的 REST API,其中我使用 Spring Security (spring-security-core
e spring-security-config
) 来保护不同的端点.
身份验证是通过使用包含具有两组不同角色的用户的本地数据库完成的:ADMIN
和USER
.USER
应该能够GET
所有 API 端点并POST
到基于routeA
的端点.ADMIN
应该能够与USER
加上POST
和DELETE
对基于`routeB的端点执行相同的操作>
但是我得到的行为是我可以对任何端点执行 GET
请求,但 POST
请求总是返回 HTTP 403 Forbidden
任一类型的用户 - ADMIN
和 USER
- 根据我的 SecurityConfiguration
,这不是我所期望的.
对我缺少什么有任何想法吗?
<小时>SecurityConfiguration.java
@Configuration@启用网络安全公共类 SecurityConfiguration 扩展了 WebSecurityConfigurerAdapter {私有静态最终记录器记录器 = LoggerFactory.getLogger(SecurityConfiguration.class);@自动连线私有 RESTAuthenticationEntryPoint authenticationEntryPoint;@自动连线私有数据源数据源;@覆盖public void configure(AuthenticationManagerBuilder builder) 抛出异常 {logger.info("使用数据库作为身份验证提供者.");builder.jdbcAuthentication().dataSource(dataSource).passwordEncoder(new BCryptPasswordEncoder());}@覆盖protected void configure(HttpSecurity http) 抛出异常 {http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER").antMatchers(HttpMethod.POST, "/routeA/*").hasAnyRole("ADMIN", "USER").antMatchers(HttpMethod.POST, "/routeB/*").hasRole("ADMIN").antMatchers(HttpMethod.DELETE, "/routeB/*").hasRole("ADMIN").and().requestCache().requestCache(new NullRequestCache()).and().httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().cors();}@豆公共 CorsConfigurationSource corsConfigurationSource() {最终 CorsConfiguration 配置 = new CorsConfiguration();configuration.setAllowedOrigins(Arrays.asList("*"));configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));configuration.setAllowCredentials(true);configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));最终 UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", 配置);返回源;}
RouteBController .java
@RestController公共类 RouteBController {静态最终记录器记录器 = LoggerFactory.getLogger(RouteBController.class);公共 RouteBController() { }@RequestMapping(value = "routeB",产生 = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)公共字符串 getStuff() {return "有一个你好世界!";}@RequestMapping(value = "routeB",产生 = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)公共字符串 postStuff() {return "发布了一个你好世界!";}}
RESTAuthenticationEntryPoint.java
@Component公共类 RESTAuthenticationEntryPoint 扩展 BasicAuthenticationEntryPoint {@覆盖public void afterPropertiesSet() 抛出异常 {setRealmName("AppNameHere");super.afterPropertiesSet();}}
BEFORE 禁用 CSFR 作为解决此问题的一种方式,请查看 Mohd Waseem 的回答 以更好地理解为什么它很重要并了解如何正确设置它.正如 RCaetano 所说,CSFR 是来帮助我们抵御攻击的,不应盲目禁用它.
由于这个答案仍然解释了我最初问题中的两个问题,我将其作为标记答案,以提高人们对 CSFT 和安全路线可能存在的问题的认识,但不要从字面上理解.
SecurityConfiguration.java
中有 2 个问题使其行为异常.
虽然 403 Forbidden
错误消息没有包含任何关于失败原因的消息指示(参见下面的示例),但事实证明这是由于 CSRF 已启用.禁用它允许处理 POST
和 DELETE
请求.
<代码>{时间戳":2018-06-26T09:17:19.672+0000",状态":403,错误":禁止",消息":禁止",路径":/routeB";}
还有 antMatched(HttpMethod, String)
中用于 RouteB
的表达式是不正确的,因为 /routeB/*
期望它具有 / 之后的>东西.正确的配置是 /routeB/**
因为更多路径可以存在(或不).
更正的 SecurityConfiguration.java
是
@Overrideprotected void configure(HttpSecurity http) 抛出异常 {http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER").antMatchers(HttpMethod.POST, "/routeA/**").hasAnyRole("ADMIN", "USER").antMatchers(HttpMethod.POST, "/routeB/**").hasRole("ADMIN").antMatchers(HttpMethod.DELETE, "/routeB/**").hasRole("ADMIN").and().requestCache().requestCache(new NullRequestCache()).and().httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().cors().and().csrf().disable();}
<块引用>
来源: StackOverflow em Português
I'm developing a REST API based on Spring Boot (spring-boot-starter-web
) where I use Spring Security (spring-security-core
e spring-security-config
) to protect the different endpoints.
The authentication is done by using a local database that contains users with two different sets of roles: ADMIN
andUSER
. USER
should be able toGET
all API endpoints and POST
to endpoints based onrouteA
. ADMIN
should be able to do the same asUSER
plus POST
andDELETE
to endpoints based on `routeB
However the behavior I'm getting is that I can do GET
requests to any endpoint but POST
requests always return HTTP 403 Forbidden
for either type of user - ADMIN
and USER
- which is not expected what I'm expecting based on my SecurityConfiguration
.
Any ideas of what am I missing?
SecurityConfiguration.java
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(SecurityConfiguration.class);
@Autowired
private RESTAuthenticationEntryPoint authenticationEntryPoint;
@Autowired
private DataSource dataSource;
@Override
public void configure(AuthenticationManagerBuilder builder) throws Exception {
logger.info("Using database as the authentication provider.");
builder.jdbcAuthentication().dataSource(dataSource).passwordEncoder(new BCryptPasswordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().
authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.POST, "/routeA/*").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.POST, "/routeB/*").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/routeB/*").hasRole("ADMIN").and().
requestCache().requestCache(new NullRequestCache()).and().
httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().
cors();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("HEAD", "GET", "POST", "PUT", "DELETE", "PATCH"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
RouteBController .java
@RestController
public class RouteBController {
static final Logger logger = LoggerFactory.getLogger(RouteBController.class);
public RouteBController() { }
@RequestMapping(value = "routeB", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.GET)
public String getStuff() {
return "Got a hello world!";
}
@RequestMapping(value = "routeB", produces = MediaType.APPLICATION_JSON_UTF8_VALUE, method = RequestMethod.POST)
public String postStuff() {
return "Posted a hello world!";
}
}
RESTAuthenticationEntryPoint.java
@Component
public class RESTAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
@Override
public void afterPropertiesSet() throws Exception {
setRealmName("AppNameHere");
super.afterPropertiesSet();
}
}
BEFORE disabling the CSFR as a way of fixing this issue, please check the resources on Mohd Waseem's answer to better understand why it is important and to have an idea of how it can be properly set up. As RCaetano has said, CSFR is here to help us from attacks and it should not be disabled blindly.
Since this answer still explained the 2 issues on my original questions, I'll leave it as the marked answer to create awareness about possible issues with the CSFT and security routes but don't take it literally.
There were 2 issues in SecurityConfiguration.java
that made it misbehave.
Although the 403 Forbidden
error message didn't contain any message indication of why it was failing (see example below) it turns out it was due to having CSRF enabled. Disabling it allowed for POST
and DELETE
requests to be processed.
{
"timestamp": "2018-06-26T09:17:19.672+0000",
"status": 403,
"error": "Forbidden",
"message": "Forbidden",
"path": "/routeB"
}
Also the expression used in antMatched(HttpMethod, String)
for RouteB
was incorrect because /routeB/*
expects it to have something after /
. The correct configurtion is /routeB/**
since more paths can be present (or not).
The corrected SecurityConfiguration.java
is
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().
authorizeRequests().antMatchers(HttpMethod.GET, "/**").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.POST, "/routeA/**").hasAnyRole("ADMIN", "USER")
.antMatchers(HttpMethod.POST, "/routeB/**").hasRole("ADMIN")
.antMatchers(HttpMethod.DELETE, "/routeB/**").hasRole("ADMIN").and().
requestCache().requestCache(new NullRequestCache()).and().
httpBasic().authenticationEntryPoint(authenticationEntryPoint).and().
cors().and().
csrf().disable();
}
Source: StackOverflow em Português
这篇关于尽管有 SecurityConfig,Spring Security 仍会阻止 POST 请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!