如何使Spring Security允许匿名的POST请求?

huangapple go评论59阅读模式
英文:

How to make Spring Security allow anonymous POST requests?

问题

我有一个Spring Boot网络应用程序其中大多数端点都需要身份验证然而少数映射将允许匿名访问它们是通用规则的例外

我无法使这对于POST调用起作用它们总是得到403错误

安全配置...
```java
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests().regexMatchers("/","/posthello").anonymous()
        .and()
            .authorizeRequests().anyRequest().authenticated();
    }
}

控制器...

@RestController
public class HelloController {

    // 这在匿名调用时返回HTTP 200和正文
    @GetMapping("/")
    public String helloWorld() {
        return "Hello World!";
    }

    // 正如预期的那样,这需要身份验证
    @GetMapping("/gethello")
    public String getHelloWorld(String body) {
        return "You got: Hello, World!";
    }

    // 即使它被期望为例外情况,这总是在匿名调用时返回HTTP 403
    @PostMapping("/posthello")
    public String postHelloWorld(@RequestBody String body) {
        return "You posted: " + body;
    }
}

<details>
<summary>英文:</summary>

I have a Spring Boot web application, where most endpoints require authentication. However, a few mappings shall allow anonymous access; they are exceptions from the general rule. 

I cannot get this to work for POST calls, they are always getting 403. 

The security configuration...

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().regexMatchers("/", "/posthello").anonymous()
.and()
.authorizeRequests().anyRequest().authenticated();
}
}

The controller...

@RestController
public class HelloController {

// This returns HTTP 200 and body on anonymous calls
@GetMapping(&quot;/&quot;) 
public String helloWorld() {
	return &quot;Hello World!&quot;;
}

// This demands authentication, as expected
@GetMapping(&quot;/gethello&quot;) 
public String getHelloWorld(String body) {
	return &quot;You got: Hello, World!&quot;;
}

// This always returns HTTP 403 on anonymous calls, 
// even though it is supposed to be excepted
@PostMapping(&quot;/posthello&quot;) 
public String postHelloWorld(@RequestBody String body) {
	return &quot;You posted: &quot; + body;
}	

}


</details>


# 答案1
**得分**: 5

Patel Romil正确指出403错误是由CSRF引起的,禁用CSRF将禁用该保护。他明智地提醒不要在生产应用程序中这样做。

禁用整个站点的CSRF的替代方法是指定允许的端点列表,如下所示:

```java
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
                .ignoringAntMatchers("/posthello")
                .and()
            .authorizeRequests()
                .antMatchers(HttpMethod.POST, "/posthello").anonymous()
                .anyRequest().authenticated();
    }
}

尽管如此,真正的解决方案可能是配置应用程序以使用CSRF令牌。没有CSRF保护,任意第三方Web应用程序可以调用POST /posthello

英文:

Patel Romil is correct that the 403 is caused by CSRF and that disabling CSRF would disable that protection. He's also wise to warn against doing that in a production application.

An alternative to disabling CSRF for the entire site is specifying an allowlist of endpoints, like so:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf()
                .ignoringAntMatchers(&quot;/posthello&quot;)
                .and()
            .authorizeRequests()
                .antMatchers(HttpMethod.POST, &quot;/posthello&quot;).anonymous()
                .anyRequest().authenticated();
    }
}

That said, the real solution is likely to configure the application to use CSRF tokens. Without CSRF protection, arbitrary third-party web applications can invoke POST /posthello.

答案2

得分: 2

您可以像这样提及不需要身份验证的端点。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().authorizeRequests()
        .antMatchers("/", "/error", "/user/signup", "/user/signin", "/swagger-ui.html")
        .permitAll().anyRequest().authenticated().and().sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
英文:

You can mention the endpoints like this, for which authenication is not required.

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests()
            .antMatchers(&quot;/&quot;, &quot;/error&quot;, &quot;/user/signup&quot;, &quot;/user/signin&quot;, &quot;/swagger-ui.html&quot;)
            .permitAll().anyRequest().authenticated().and().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

答案3

得分: 1

禁止访问错误可能是由于 CSRF 引起的。您可以尝试在 configure 方法中禁用 CSRF,如下所示。

 http
      .csrf().disable()
      // 其他配置

或者,您可以在发送 POST 请求的表单中添加以下隐藏字段。 (这适用于 Thymeleaf。您可以根据您的视图进行调整)

<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
英文:

Forbidden errors might occur due to csrf. You can try disabling the csrf in your configure method as below.

 http
      .csrf().disable()
      // remaining configurations

Alternatively, you can add the following hidden field in your form which is sending the POST request. (It is for thymeleaf. You can get this as per your view)

&lt;input type=&quot;hidden&quot; th:name=&quot;${_csrf.parameterName}&quot; th:value=&quot;${_csrf.token}&quot; /&gt;

答案4

得分: 1

你需要使用csrf().disable()来禁用CSRF令牌。我建议您在生产环境中使用CSRF令牌。除此之外,您可以通过在antMatchers中使用HttpMethod.method来允许特定方法的anonymous()访问。

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.POST, "/posthello").anonymous()
            .anyRequest().authenticated();
    }
}

或者

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.POST, "/posthello").anonymous()
            .antMatchers("**/**").authenticated();
    }
}

为了在生产环境中启用CSRF,我在这里添加了更多细节:
回答1回答2

英文:

You have to disable the CSRF Tokens using csrf().disable(). I recommended you to use the CSRF Tokens in production. Along with that, you may allow the anonymous() access for the specific methods by using the HttpMethod.method in antMatchers

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests()
			.antMatchers(HttpMethod.POST, &quot;/posthello&quot;).anonymous()
            .anyRequest().authenticated();
    }
}

OR

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
		http
            .csrf().disable()
            .authorizeRequests()
            .antMatchers(HttpMethod.POST, &quot;/posthello&quot;).anonymous()
            .antMatchers(&quot;**/**&quot;).authenticated();
    }
}

To enable the CSRF in production I have added the more details here
Answer 1, Answer 2

huangapple
  • 本文由 发表于 2020年9月17日 17:42:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/63935339.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定