Spring Security:来自 UserDetailsService 的自定义异常消息
Posted
技术标签:
【中文标题】Spring Security:来自 UserDetailsService 的自定义异常消息【英文标题】:Spring Security: Custom exception message from UserDetailsService 【发布时间】:2013-06-30 15:35:11 【问题描述】:当用户尝试使用不正确的凭据登录或用户因某种原因被禁用时,我能够显示 SPRING_SECURITY_LAST_EXCEPTION.message(“错误凭据”)。
我想在用户被禁用的情况下显示自定义消息,而不是显示“错误凭据”而是说“您已被禁用......等等,等等......”。我该怎么做?
我正在使用 UserDetailsService 在 Spring Security 中提供用户名/密码。
【问题讨论】:
您是否尝试过***.com/questions/1373407/… 中描述的方法? 部分有效。我可以获得自定义消息,但是,它总是返回为 AbstractUserDetailsAuthenticationProvider.badCredentials 配置的消息。即使我抛出 DisabledException,我也会收到与我的 jsp 页面中为 badCredentials 定义的消息相同的消息 请说明您使用的是什么版本,从哪里抛出异常以及在哪里显示消息。最好发布您正在使用的实际网络安全配置。 春季版本 3.1.2。我的实现 UserDetailsService 的类抛出异常,并使用 $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) 在您的 UserDetailsService 中,使用您喜欢的任何消息键抛出上述异常:
throw new DisabledException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.disabled", "User is disabled"));
这里的消息是SpringSecurityMessageSource.getAccessor()
【讨论】:
Ritesh,感谢您的回复。起作用的部分是隐藏 UserNotFoundException。但是,现在我收到消息“未找到名为 xyz 的用户”,即使我使用不同的消息抛出自定义异常。 Jayz,通常的做法是仅在找不到用户时才从 UserDetailsService 抛出异常(默认情况下,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:来自 UserDetailsService 的自定义异常消息的主要内容,如果未能解决你的问题,请参考以下文章
在 Grails Spring 应用程序中获取 LDAP 属性 memberof
Spring Security:来自 UserDetailsService 的自定义异常消息