Spring安全配置:HTTP 403错误

102

我正试图使用Web上的指南,使用Spring Security来保护我的网站。

因此,在我的服务器端,我有以下类:

我的WebSecurityConfigurerAdapter:

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ApplicationContextAware {

    @Override
    protected void registerAuthentication(AuthenticationManagerBuilde rauthManagerBuilder) throws Exception {
        authManagerBuilder.inMemoryAuthentication().withUser("user").password("password").roles("ADMIN");
    }
}

我的控制器:

@Controller
//@RequestMapping("/course")
public class CourseController implements ApplicationContextAware {

    @RequestMapping(value="/course", method = RequestMethod.GET, produces="application/json")
    public @ResponseBody List<Course> get(  // The criterion used to find.
        @RequestParam(value = "what", required = true) String what,
        @RequestParam(value = "value", required = true) String value) {
        //.....
    }

    @RequestMapping(value = "/course", method = RequestMethod.POST, produces = "application/json")
    public List<Course> upload(@RequestBody Course[] cs) {
        
    }
}

让我感到非常困惑的是,服务器对POST/DELETE方法没有响应,而GET方法却正常工作。顺便说一下,我在客户端使用了RestTemplate

异常信息如下:

Exception in thread "main" org.springframework.web.client.HttpClientErrorException: 403 Forbidden
    at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
    at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:574)
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:530)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:487)
    at org.springframework.web.client.RestTemplate.delete(RestTemplate.java:385)
    at hello.Application.createRestTemplate(Application.java:149)
    at hello.Application.main(Application.java:99)

我在互联网上搜索了数天,仍然毫无头绪。请帮忙,非常感谢。


1
roles("ADMI N")。'I'和'N'之间有一个空格。 - Enrico Giurin
9个回答

230
这个问题可能是由于CSRF保护引起的。如果用户不会在Web浏览器中使用您的应用程序,那么可以安全地禁用CSRF保护。否则,您应该确保在请求中包含CSRF令牌
禁用CSRF保护,可以使用以下方法:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig
    extends WebSecurityConfigurerAdapter implements ApplicationContextAware {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            // ...
            .csrf().disable();
    }

    @Override
    protected void registerAuthentication(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
        authManagerBuilder
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("ADMIN");
    }
}

3
谢谢 Rob。这是跨站请求伪造问题。是的,我不希望我的用户使用网络浏览器来使用我的应用程序。客户端工作正常。但在服务器端,我得到了以下错误信息:o.s.web.servlet.PageNotFound:不支持请求方法'POST'很奇怪。我应该忽略它吗? - ken
4
我认为“PageNotFound”是一个单独的问题,需要被解决。很可能你需要发布另一个带有更多关于该错误的信息的问题。 - Rob Winch
1
禁用 csrf 安全配置确实解决了我的问题。我发现很难跟上 Spring starters 带来的所有这些隐藏的自动功能。 - Ionut Ciuta
大家好,我的情况不是关于csrf的问题。我的代理将请求转发到后端时使用的是http而不是https。这也导致了403错误,并且很难跟踪,因为Spring也仅拒绝POST和DELETE请求(即更改状态的请求)。我不得不添加转发头配置才能使其正常工作。 - zakaria amine

8

该问题很可能是由于CSRF保护引起的,和顶部评论一致。然而,使用此配置,该方法会取消Spring Security。

因此,您可以使用以下代码:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();

        auth
                .inMemoryAuthentication()
                    .withUser("admin")
                        .password(encoder.encode("admin"))
                        .roles("ADMIN", "USER")
                .and()
                    .withUser("user")
                        .password(encoder.encode("password"))
                        .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic();

        http.csrf().disable();
    }
}

5

这个问题可能与CSRF或CORS安全保护有关。

  • 对于CSRF:如果应用程序用户没有使用浏览器,则可以禁用它。
  • 对于CORS:您可以指定来源并允许HTTP方法。

以下代码禁用了CSRF并允许所有来源和HTTP方法,请在使用时注意。

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter  implements WebMvcConfigurer {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable();
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedMethods("*");
    }

}

在生产环境中禁用csrf()是否危险? - Eltac Shikhsaidov
2
不要禁用 CSRF。这是一个巨大的安全风险。如果你不知道这个,我强烈建议在禁用它之前去“查找”一下它是什么。 - Jp Silver

4
我在将服务升级到Spring Boot 3后遇到了这个问题。自动测试开始以403状态失败。经过很多头痛,我发现这是由于从URL匹配中删除尾随斜杠引起的。 此更改在此处描述。 因此,请检查您是否调用了正确的URL。

错误:

/api/foo/

正确:

/api/foo

2
我也找了好几天!只需在configure方法中禁用CSRF,使用http.csrf().disable();即可使我的put请求停止收到403错误。

1
我发帖是为了以后其他人有用。我花了几个小时寻找失败的原因,最终我找到了解决方案。在Postman中向http://localhost:8080/login/进行POST请求与向http://localhost:8080/login进行POST请求不同(在请求末尾加上“/”会返回403禁止访问)。

不,这对我来说并不是这种情况!我必须禁用CSRF。 - Wale

0

请检查您通过“Header”发送的令牌,同时在数据库中查询相同的令牌是否存在。

注意:以上仅适用于使用Spring Boot令牌身份验证机制的情况。


0
目前,对于Spring Security 6.1.3来说,以下配置已足够实现基本身份验证。
   @Bean
   public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity)throws Exception {
  httpSecurity.httpBasic(Customizer.withDefaults());
  return httpSecurity.build(); }

-5
http.httpBasic().disable();
http.authorizeRequests().antMatchers("/signup").permitAll().antMatchers("/*")
     .fullyAuthenticated().and().formLogin()
     .and().csrf().disable();
http.csrf().disable();

3
仅限代码答案不受鼓励。 - michaelmesser
请解释您的答案。 - ASR4
1
为什么会有多个 .csrf().disable()? - Emre Can Geçer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接