Spring Security:来自 UserDetailsS​​ervice 的自定义异常消息

Posted

技术标签:

【中文标题】Spring Security:来自 UserDetailsS​​ervice 的自定义异常消息【英文标题】:Spring Security: Custom exception message from UserDetailsService 【发布时间】:2013-06-30 15:35:11 【问题描述】:

当用户尝试使用不正确的凭据登录或用户因某种原因被禁用时,我能够显示 SPRING_SECURITY_LAST_EXCEPTION.message(“错误凭据”)。

我想在用户被禁用的情况下显示自定义消息,而不是显示“错误凭据”而是说“您已被禁用......等等,等等......”。我该怎么做?

我正在使用 UserDetailsS​​ervice 在 Spring Security 中提供用户名/密码。

【问题讨论】:

您是否尝试过***.com/questions/1373407/… 中描述的方法? 部分有效。我可以获得自定义消息,但是,它总是返回为 AbstractUserDetailsAuthenticationProvider.badCredentials 配置的消息。即使我抛出 DisabledException,我也会收到与我的 jsp 页面中为 badCredentials 定义的消息相同的消息 请说明您使用的是什么版本,从哪里抛出异常以及在哪里显示消息。最好发布您正在使用的实际网络安全配置。 春季版本 3.1.2。我的实现 UserDetailsS​​ervice 的类抛出异常,并使用 $sessionScope["SPRING_SECURITY_LAST_EXCEPTION"].message 显示在我的登录 jsp 页面中 【参考方案1】:

您需要将AbstractUserDetailsAuthenticationProvider 的 hideUserNotFoundExceptions 属性设置为 false。 (这意味着这个解决方案依赖于 Spring Security 代码,将来可能会改变)。

步骤如下:

(1) 定义一个 DaoAuthenticationProvider bean(如果您已经有一个,则将其 hideUserNotFoundExceptions 属性设置为 false)。这是 Java 配置样式:

    @Bean
public AuthenticationProvider daoAuthenticationProvider() 
    DaoAuthenticationProvider impl = new DaoAuthenticationProvider();
    impl.setUserDetailsService(yourUserDetailsService());
    impl.setHideUserNotFoundExceptions(false) ;
    return impl ;

(2) 使用上述提供者配置身份验证管理器:

<authentication-manager alias="authenticationManager">
    <authentication-provider ref="daoAuthenticationProvider"/>
<!-- other providers if any -->
</authentication-manager>

(3) 创建一个扩展UsernameNotFoundException的异常:

    public class DisabledException extends UsernameNotFoundException 

    public DisabledException(String msg) 
    super(msg);
    

    /* other constructors */    

(4) 在您的 UserDetailsS​​ervice 中,使用您喜欢的任何消息键抛出上述异常:

    throw new DisabledException(messages.getMessage(
                        "AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled"));

这里的消息是SpringSecurityMessageSource.getAccessor()

【讨论】:

Ritesh,感谢您的回复。起作用的部分是隐藏 UserNotFoundException。但是,现在我收到消息“未找到名为 xyz 的用户”,即使我使用不同的消息抛出自定义异常。 Jayz,通常的做法是仅在找不到用户时才从 UserDetailsS​​ervice 抛出异常(默认情况下,BadCredentialsException 将与消息键 AbstractUserDetailsAuthenticationProvider.badCredentials 一起抛出)。如果要指示禁用的用户,则不应抛出异常并将启用标志的用户返回为 false(默认情况下,将使用消息键 AbstractUserDetailsAuthenticationProvider.disabled 抛出 DisabledException)。 (也许这首先应该是我的答案) Ritesh,如果应用程序默认抛出 DisabledException,那么我不会发布这个问题。它不是。即使用户被禁用,它也会抛出带有消息键 AbstractUserDetailsAuthenticationProvider.badCredentials 的 BadCredentialsException 好的。查看 AbstractUserDetailsAuthenticationProvider (3.1.0.RELEASE) 的代码,如果用户详细信息服务没有异常并且用户被禁用,则有一个私有类 DefaultPreAuthenticationChecks 抛出 DisabledException。请参阅 preAuthenticationChecks.check(user)。我不确定为什么它不起作用;无论如何,我很高兴答案有助于解决问题。 [与提出的问题无关] 我们也可以为已解决的问题提供悬赏吗?【参考方案2】:

在类路径中创建一个属性文件,例如 loginMessage.properties

在该属性文件中,指定

AbstractUserDetailsAuthenticationProvider.badCredentials=输入的用户名/密码不正确。

在您的 applicationContext.xml 中添加以下 bean,

<bean id="messageSource"   
    class="org.springframework.context.support.ResourceBundleMessageSource">  
    <property name="basenames">  
        <list>
            <value>loginMessage</value>
        </list>
    </property>
</bean>

在userDao中,如果结果为空

throw new UsernameNotFoundException("");

之后,您会收到类似用户名/密码输入不正确的消息。而不是坏凭据

【讨论】:

以上是关于Spring Security:来自 UserDetailsS​​ervice 的自定义异常消息的主要内容,如果未能解决你的问题,请参考以下文章

在 Grails Spring 应用程序中获取 LDAP 属性 memberof

Spring Security:来自 UserDetailsS​​ervice 的自定义异常消息

列出来自 Spring Security 的用户

来自自定义表的 Spring Security 身份验证

来自服务的 Grails Spring Security 身份验证

Spring Security - 来自 JWT 的自定义主体