添加'Authorization'标头会导致Spring Security保护允许的端点

时间:2019-03-28 13:27:21

标签: java spring-boot http spring-security basic-authentication

所以,我的WebSecurityConfigurerAdapter中有这个

public class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // Use this configuration for endpoints starting with 'api'
                .antMatcher("/api/**")
                // Do not secure endpoints receiving callbacks
                .authorizeRequests().antMatchers(""/api/v1/notification").permitAll()
                // Allow only users with role "ROLE_API"
                .anyRequest().hasRole(Users.UserRoles.ROLE_API.role.replace("ROLE_", ""))
                .and()
                .httpBasic()
                .and()
                // Do not create any sessions
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // Disable csrf
                .csrf().disable();            

    }

}

不应保护/api/v1/notification

。如果我在Authorization: Basic abcd标头中调用不带HTTP的端点,则允许该请求,但是如果我添加Authorization: Basic abcd标头,则会得到一个401 http响应代码。

注意:Basic abcd只是随机的,因此我的数据库中没有这样的用户

问题是,为什么在http标头中添加Authorization...会使端点再次受到保护?

1 个答案:

答案 0 :(得分:1)

很好的问题,这可能会造成混淆,因为这意味着只有密码错误的合法客户端才能被拒绝访问该页面,而其他世界无需凭据即可看到该页面。

实际上,这是设计使然。一般来说,授权系统需要先知道用户是谁,然后再知道用户是否可以执行X,Y或Z操作。即使使用公共端点,当用户处于上下文中时,端点的行为也可能会有所不同。因此,实际上,它们是首先进行身份验证的独立系统:如果请求提供凭据,则框架将尝试对用户进行身份验证,并相应地接受或拒绝该请求。

一个选项

我知道您并没有要求解决该问题(您可能对行为完全满意,并且很好奇),但是您可以使用BasicAuthenticationFilter将其配置为忽略故障,只是为了该端点:

static class IgnoreFailuresBasicAuthenticationFilter extends BasicAuthenticationFilter {
    private final BasicAuthenticationFilter everythingElse;

    public IgnoreFailuresBasicAuthenticationFilter(BasicAuthenticationFilter everythingElse) {
        super(everythingElse.getAuthenticationManager());
        this.everythingElse = everythingElse;
    }

    protected void doFilterInternal(request, response, chain) {
        if ("/api/v1/notification".equals(request.getPathInfo())) {
            super.doFilterInternal(request, response, chain);
        } else {
            this.everythingElse.doFilterInternal(request, response, chain);
        }
    }
}

然后替换DSL中的过滤器:

http
    .httpBasic()
        .withObjectPostProcessor(
            new ObjectPostProcessor<BasicAuthenticationFilter>() {
                public BasicAuthenticationFilter postProcess(BasicAuthenticationFilter filter) {
                    return new IgnoreFailuresBasicAuthenticationFilter(filter);
                }
            });

此操作将允许过滤器链继续,即使基本身份验证失败也是如此。结果是,在身份验证失败的情况下,您将获得403而不是401。