Spring Security匿名401而不是403

时间:2015-06-04 11:47:29

标签: java spring spring-security spring-boot

我遇到了Spring安全性中的默认行为问题,其中包含Java Config提供的授权请求。

http
       ....
       .authorizeRequests()
          .antMatchers("/api/test/secured/*").authenticated()

当我在没有登录(使用匿名用户)的情况下调用例如/api/test/secured/user时,它返回403 Forbidden。当匿名用户想要通过authenticated()@PreAuthorize资源获得安全保护时,是否有一种简单的方法可以将状态更改为401 Unauthorized?

5 个答案:

答案 0 :(得分:15)

使用spring security 4.x已经有了一个类

org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint 

Spring boot还包括一个

org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint

并且必须设置他们要求开发人员使用符合规范401 responses requires that header WWW-Authenticate的两个好处,例如401响应可能是:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="example",
                   error="invalid_token",
                   error_description="The access token expired"

因此,在安全配置中,您可以定义并自动装配类

的bean

所以例如使用spring boot app:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{

    @Bean
    public Http401AuthenticationEntryPoint securityException401EntryPoint(){

        return new Http401AuthenticationEntryPoint("Bearer realm=\"webrealm\"");
    }

    @Autowired
    private Http401AuthenticationEntryPoint authEntrypoint;
...
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
                .antMatchers("/login").anonymous()
                .antMatchers("/").anonymous()
                .antMatchers("/api/**").authenticated()
            .and()
            .csrf()
                .disable()
                .headers()
                .frameOptions().disable()
            .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .logout()
                .permitAll()
         .exceptionHandling().authenticationEntryPoint(authEntrypoint);
}

相关的一行是:

 .exceptionHandling().authenticationEntryPoint(authEntrypoint);

答案 1 :(得分:10)

我有解决方案here

http
   .authenticationEntryPoint(authenticationEntryPoint)

AuthenticationEntryPoint源代码:

@Component
public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint {

    private final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class);

    /**
     * Always returns a 401 error code to the client.
     */
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2) throws IOException,
            ServletException {

        log.debug("Pre-authenticated entry point called. Rejecting access");
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied");
    }
}

答案 2 :(得分:7)

从Spring Boot 2开始,类Http401AuthenticationEntryPoint已被删除(请参阅Spring Boot Issue 10725)。

使用HttpStatusEntryPoint而不是Http401AuthenticationEntryPoint和HttpStatus.UNAUTHORIZED:

http.exceptionHandling()
    .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));

答案 3 :(得分:0)

Spring Boot 2中使用lambda表达式的一种简单方法:

@Override
public void configure(HttpSecurity http) throws Exception {
    http.
        ...
        .exceptionHandling()
            .authenticationEntryPoint((request, response, e) -> {
                response.setStatus(HttpStatus.UNAUTHORIZED.value());
                response.setContentType("application/json");
                response.getWriter().write("{ \"error\": \"You are not authenticated.\" }");
            })
        ...
}

答案 4 :(得分:0)

谁对工作机制感兴趣。
如果你不设置 http.exceptionHandling().authenticationEntryPoint() spring 将使用 defaultAuthenticationEntryPoint() 而方法 ExceptionHandlingConfigurer.createDefaultEntryPoint() 将返回 new Http403ForbiddenEntryPoint()
因此,只需创建 Http401UnauthorizedEntryPoint()。上面回答了怎么做,没有重复。

附言实际适用于 Spring Security 5.2.5.RELEASE