AuthenticationProvider中抛出的AuthenticationException被映射到ExceptionTranslationFilter中的AccessDeniedException

时间:2019-05-08 08:57:27

标签: spring spring-security

已经编写了一个自定义AuthenticationProvider(调用服务,然后再调用一个外部URL来验证给定的凭据),我想根据我传递给它的消息来自定义身份验证失败时收到的错误消息。 AuthenticationException的实例(因此e.getMessage()在下面的代码中传递给BadCredentialsExceptoin)。

@Component
public class TapasAuthenticationProvider implements AuthenticationProvider {

    @Override
    public TapasAuthentication authenticate(Authentication authentication) throws AuthenticationException {
        String userName = authentication.getName();
        String password = authentication.getCredentials().toString();

        try {
            AuthenticationResponse authResponse = authenticationService.authenticate(userName, password);
            return new TapasAuthentication(mapToAuthenticatedUser(authResponse, userName, password), password);
        } catch (AuthenticationFailedException e) {
            // Note that AuthenticationFailedException is a self-written exception, thrown by the authenticationService.
            log.error("Authentication failed: ", e);
            throw new BadCredentialsException(e.getMessage());
        }
    }

}

现在,我查看了如何映射AuthenticationException,并发现应该使用AuthenticationEntryPoint。所以我创建了一个并将其添加到我的SecuritySetup中:

@Component
public class TapasAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
            throws IOException, ServletException {
        System.out.println(authException.getMessage());
        // More code to be added once exception is what I expect.
    }

}

    @Autowired
    private TapasAuthenticationEntryPoint authenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
                .and()
                .authorizeRequests().anyRequest().authenticated().and().httpBasic()
                .and()
                .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
                .and()
                .csrf().disable();
    }

这成功触发了AuthenticationEntryPoint,但是我得到了一个BadCredentialsException,而不是InsufficientAuthenticationException。我检查了此异常的起源,它来自ExceptionTranslationFilter的handleSpringSecurityException。在这里,例外情况是AccessDeniedException而不是AuthenticationException

    private void handleSpringSecurityException(HttpServletRequest request,
            HttpServletResponse response, FilterChain chain, RuntimeException exception)
            throws IOException, ServletException {
        if (exception instanceof AuthenticationException) {
            // I would except to enter this if-statement, but exception is not what I expect
            sendStartAuthentication(request, response, chain,
                    (AuthenticationException) exception);
        }
        else if (exception instanceof AccessDeniedException) {
            ....
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authenticationTrustResolver.isAnonymous(authentication) || authenticationTrustResolver.isRememberMe(authentication)) {
                // Instead code comes here, and creates an InsufficientAuthenticationException.

                sendStartAuthentication(
                        request,
                        response,
                        chain,
                        new InsufficientAuthenticationException(
                            messages.getMessage(
                                "ExceptionTranslationFilter.insufficientAuthentication",
                                "Full authentication is required to access this resource")));
            }
            ...
        }
    }

为什么异常与AuthenticationProvider中引发的异常不匹配?以及如何将数据从AuthenticationProvider传递回用户?

1 个答案:

答案 0 :(得分:0)

找出HttpBasicConfigurer调用返回的.basicSecurity(),也可以注册AuthenticationEntryPoint。以这种方式注册时,Provider引发的异常的确会出现在入口点。

安全配置如下:

    @Autowired
    private TapasAuthenticationEntryPoint authenticationEntryPoint;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
                .and()
                .authorizeRequests().anyRequest().authenticated()
                .and()
                .httpBasic().authenticationEntryPoint(authenticationEntryPoint)
                .and()
                .csrf().disable();
    }