这个教程是我在往项目中一点一点添加 Spring Security的过程的一个笔记,也是我学习 Spring Security的一个过程。
在解决这个问题之前要先说一点authentication-provider默认加载的是DaoAuthenticationProvider类。
完成了上一章的内容后在测试的时候发现在UserDetailsService中抛出的UsernameNotFoundException无法被捕获。于是找到DaoAuthenticationProvider,源码看了好几遍没有看出端倪。然后直接查看最顶级的接口AuthenticationProvider。发现它只有一个方法如下
- Authentication authenticate(Authentication authentication) throws AuthenticationException;
然后找到DaoAuthenticationProvider的父类AbstractUserDetailsAuthenticationProvider的authenticate方法,发现了这段代码。
- try {
- user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
- } catch (UsernameNotFoundException notFound) {
- logger.debug("User '" + username + "' not found");
- if (hideUserNotFoundExceptions) {
- throw new BadCredentialsException(messages.getMessage(
- "AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"));
- } else {
- throw notFound;
- }
- }
- <sec:authentication-manager>
- <sec:authentication-provider ref="authenticationProvider" />
- </sec:authentication-manager>
- <bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
- <property name="hideUserNotFoundExceptions" value="false" />
- <property name="userDetailsService" ref="userDetailService" />
- <property name="userCache" ref="userCache" />
- <property name="messageSource" ref="messageSource" />
- <property name="passwordEncoder" ref="passwordEncode" />
- <property name="saltSource" ref="saltSource" />
- </bean>
- <!-- 配置密码加密类 -->
- <bean id="passwordEncode" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
- <bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource">
- <property name="userPropertyToUse" value="username"/>
- </bean>
注意:如果在authentication-provider配置中用ref指定AuthenticationProvider则authentication-provider的子元素将都不可以用。
即下面的这种配置是错误的
- <sec:authentication-manager>
- <sec:authentication-provider ref="authenticationProvider" >
- <sec:password-encoder ref="passwordEncode">
- <sec:salt-source user-property="username"/>
- </sec:password-encoder>
- </sec:authentication-provider>
- </sec:authentication-manager>
SaltSource是一个接口有两个实现类SystemWideSaltSource和ReflectionSaltSource。
SystemWideSaltSource :只能指定固定值
ReflectionSaltSource:可以指定UserDetails的属性,这里我们用的就是它
这样的话就可以保证在抛出UsernameNotFoundException时,前台能显示出来错误信息,如下所示。
在上一章中忘了介绍如何在前台显示登录是的异常信息,在这里补上。
UsernamePasswordAuthenticationFilter认证失败后,异常信息会写到Session中,key为SPRING_SECURITY_LAST_EXCEPTION
可以通过El表达式来获取到异常的信息。
- ${sessionScope.SPRING_SECURITY_LAST_EXCEPTION.message}