使用Java配置的Spring Security:如何从自定义提供程序处理BadCredentialsException

时间:2014-02-14 12:52:44

标签: spring-security spring-java-config

我需要使用url中的令牌ID(或者可能在请求标头中)对一些休息服务进行身份验证 - 但这对于现在来说并不重要。我正在尝试使用java配置来设置它作为指导post。我的问题是我不知道如何处理从提供程序验证失败时引发的“BadCredentialsException”。这是我的安全配置:

public static class SecurityConfigForRS extends
        WebSecurityConfigurerAdapter {

    @Autowired
    TokenAuthenticationProvider tokenAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.authenticationProvider(tokenAuthenticationProvider);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean()
            throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);

        http.regexMatcher("^/rest.*")
                .addFilterBefore(
                        new TokenAuthenticationFilter(
                                authenticationManagerBean()),
                        AbstractPreAuthenticatedProcessingFilter.class)
                .and().csrf().disable();

    }
}

现在我跳过其他实现 - 如果有帮助我稍后会发布它们。

当令牌丢失或无效时,TokenAuthernticationProvider会抛出BadCredentialsException。我需要抓住这个并发回401-Unauthorized。有可能这样做吗?

1 个答案:

答案 0 :(得分:5)

我创建的第一个Filter是 GenericFilterBean 的子类,它不支持身份验证失败处理程序或成功处理程序。但是 AbstractAuthenticationProcessingFilter 支持成功和失败处理程序。我的过滤器就像那样简单:

public class TokenAuthenticationProcessingFilter extends
    AbstractAuthenticationProcessingFilter {

public TokenAuthenticationProcessingFilter(
        RequestMatcher requiresAuthenticationRequestMatcher) {
    super(requiresAuthenticationRequestMatcher);
}

@Override
public Authentication attemptAuthentication(HttpServletRequest request,
        HttpServletResponse response) throws AuthenticationException,
        IOException, ServletException {
    Authentication auth = new TokenAuthentication("-1");
    try {
        Map<String, String[]> params = request.getParameterMap();
        if (!params.isEmpty() && params.containsKey("auth_token")) {
            String token = params.get("auth_token")[0];
            if (token != null) {
                auth = new TokenAuthentication(token);
            }
        }
        return this.getAuthenticationManager().authenticate(auth);
    } catch (AuthenticationException ae) {
        unsuccessfulAuthentication(request, response, ae);
    }
    return auth;
}}

我的http安全性是:

    public static class SecurityConfigForRS extends
        WebSecurityConfigurerAdapter {

    @Autowired
    TokenAuthenticationProvider tokenAuthenticationProvider;

    @Override
    protected void configure(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.authenticationProvider(tokenAuthenticationProvider);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean()
            throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    protected AbstractAuthenticationProcessingFilter getTokenAuthFilter()
            throws Exception {
        TokenAuthenticationProcessingFilter tapf = new TokenAuthenticationProcessingFilter(
                new RegexRequestMatcher("^/rest.*", null));
        tapf.setAuthenticationManager(authenticationManagerBean());
        return tapf;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http);

        http.regexMatcher("^/rest.*")
                .addFilterAfter(getTokenAuthFilter(),
                        BasicAuthenticationFilter.class).csrf().disable();

    }
}

过滤器链序 很重要!我把它放在BasicAuthenticationFilter之后,它运行正常。当然可能有一个更好的解决方案,但现在这个有效!