【问题标题】:How to handle run time exceptions thrown by Spring Security AuthenticationProviders?如何处理 Spring Security AuthenticationProviders 抛出的运行时异常?
【发布时间】:2017-05-28 13:39:45
【问题描述】:

如何处理 Spring Security Authentication Providers 抛出的运行时异常?我使用的是 Spring Boot 1.4.2,但我觉得这也适用于经典的 Spring 应用程序。

假设我有一个 ActiveDirectoryLdapAuthenticationProvider 配置为针对我的公司 AD 对用户进行身份验证。当身份验证由于凭据错误而失败时,这一切都与 Spring Security 配合得很好(抛出 AuthenticationException,由 Spring Security 机制正确处理 = 应用程序返回登录屏幕并且可以显示身份验证错误)。

但是有时会发生这种情况,AD 会暂时关闭,而会抛出 org.springframework.ldap.CommunicationException。此异常是运行时异常,因此不会被 Spring 的安全机制捕获,因为它没有扩展 AuthenticationException

在这种情况下,应用程序被重定向到默认错误页面(即 /error)。我想要做的是仍然显示带有自定义消息的登录屏幕。

我发现我可以做到这一点,如果我创建类似的东西

public class ActiveDirectoryLdapExtendedAuthenticationProvider implements AuthenticationProvider {

private final ActiveDirectoryLdapAuthenticationProvider adAuthenticationProvider;

public ActiveDirectoryLdapExtendedAuthenticationProvider(ActiveDirectoryLdapAuthenticationProvider adAuthenticationProvider) {
    this.adAuthenticationProvider = adAuthenticationProvider;
}

@Override
public Authentication authenticate(Authentication a) throws AuthenticationException {

    Authentication auth = null;

    try {            
        auth = adAuthenticationProvider.authenticate(a);
    }
    catch(CommunicationException communicationException) {
        throw new AuthenticationServiceException("Could not reach User Directory. Please try again in a few minutes");
    }

    return auth;
}

这可行,但我觉得必须有更好的方法。

我尝试创建一个ControllerAdvice 带注释的类,但它没有被 POST 调用以由 Spring Security 登录。我想这是因为 POST 是由 Spring Security 过滤器处理的,它是 Servlet 过滤器,位于主 Spring MVC 调度程序 servlet 之上。

我还尝试创建一个SimpleMappingExceptionResolver 来处理CommunicationException 并重定向到登录页面,但这也不起作用,因为我的SimpleMappingExceptionResolver 也没有被调用。

我想出的另一个解决方法是解决错误页面本身的异常,例如(使用 Thymeleaf)

<div class="container error" th:switch="${exception}">
        <span  th:case="'org.springframework.ldap.CommunicationException'">Error communicating with User Directory. Please try again in a few minutes</span>
        <span  th:case="*">An unexpected error has occurred</span>
</div>

我仍然觉得应该有更好的方法。如何配置 DispatcherServlet 以确保将 CommunicationException 重定向到 /login 控制器,而不是错误页面?或者更笼统地说...我如何配置登录阶段的任何异常都显示在登录屏幕上?

【问题讨论】:

  • 你不能...它是一个Filter 并且Filter 总是在Servlet 之前执行(这在servlet 规范中定义)。所以DispatcherServlet 对此无能为力。您可以指定对容器中的特定异常执行什么操作(您需要为此修改嵌入式 tomcat 配置)。
  • @M.Deinum 我明白了.. 您可以将特定错误代码或异常类型映射到路径的部分。就个人而言,我一直在寻找更可定制的东西,例如 - 如果异常发生在登录屏幕上,则始终在登录屏幕上显示错误,否则不会。这意味着我必须映射到 MVC 视图以检查会话中的身份验证并执行此逻辑 - 如果经过身份验证,则转到默认错误页面,否则转到默认登录。也许我的理由是有缺陷的,一个意外的错误应该总是出现在一个定义明确的错误页面

标签: java spring spring-boot spring-security exception-handling


【解决方案1】:

遇到同样的问题并解决它创建自定义 Spring AuthenticationFailureHandler。它通过在自定义 AuthenticationProvider 类中抛出 BadCredentialsException 来捕获错误。

【讨论】:

    猜你喜欢
    • 2016-01-20
    • 2021-08-09
    • 2016-04-27
    • 2020-05-18
    • 2013-07-24
    • 1970-01-01
    • 2023-04-04
    • 2014-12-22
    • 2012-08-21
    相关资源
    最近更新 更多