这里给出一个简单的安全验证的实现例子,先说一下需求:
1.通过登录页面进行登录
2.用户登录前访问被保护的地址时自动跳转到登录页面
3.用户信息存储在数据表中
4.用户权限信息存在在数据表中
5.用户登录成功后访问没有权限访问的地址时跳转到登录页面
ok,以上就是一个基本的需求了,大部分的系统都是基于该需求实现登录模块的。
给出实现之前,先简单说明一下springsecurity的原理,
1.AccessDecisionManager
和我们一般实现登录验证采用filter的方式一样,springsecurity也是一个过滤器,当请求被springsecurity拦截后,会先对用户请求的资源进行安全认证,如果用户有权访问该资源,则放行,否则将阻断用户请求或提供用户登录,
在springsecurity中,负责对用户的请求资源进行安全认证的是AccessDecisionManager,它就是一组投票器的集合,默认的策略是使用一个AffirmativeBased,既只要有一个投票器通过验证就允许用户访问,
所以如果希望实现自己的权限验证策略,实现自己的投票器是一个很好的选择。
2.UserDetailsService
如果用户没有登录就访问某一个受保护的资源,则springsecurity会提示用户登录,用户登录后,由UserDetailsService来验证用户是否合法,既验证用户名和密码是否正确,同时验证用户是否具备相应的资源权限,
即对应的access的value。
如果用户验证通过,则由AccessDecisionManager来决定是否用户可以访问该资源。
下面给出具体实现:
web.xml
基本上都是这样配置,就不废话了。
1. <</span> filter >
2. <</span> filter-name > springSecurityFilterChain </</span> filter-name >
3. <</span> filter-class > org.springframework.web.filter.DelegatingFilterProxy </</span> filter-class>
4. </</span> filter >
5. <</span> filter-mapping >
6. <</span> filter-name > springSecurityFilterChain </</span> filter-name >
7. <</span> url-pattern > *.do*" access = "HODLE" />
8. <</span> logout logout-url = "/logout.do" invalidate-session = "true"
9. logout-success-url = "/logout.jsp" />
10. <</span> form-login login-page = "/index.do" default-target-url = "/frame.do"
11. always-use-default-target = "true" authentication-failure-url = "/index.do?login_error=1" />
12. <</span> session-management >
13. <</span> concurrency-control max-sessions = "1" />
14. </</span> session-management >
15. </</span> http >
<</span> beans:bean id = "loggerListener"
21. class = "org.springframework.security.authentication.event.LoggerListener" />
24.<</span> authentication-manager >
25. <</span> authentication-provider user-service-ref = "userService" >
26. <</span> password-encoder hash = "md5" />
27. </</span> authentication-provider >
28. </</span> authentication-manager >
30. <</span> beans:bean id = "userService" class = "com.piaoyi.common.security.UserService" />
33. <</span> beans:bean id = "accessDecisionManager"
34. class = "org.springframework.security.access.vote.AffirmativeBased" >
35. <</span> beans:property name = "decisionVoters" >
36. <</span> beans:list >
37. <</span> beans:bean class = "org.springframework.security.access.vote.RoleVoter" />
38. <</span> beans:bean
39. class = "org.springframework.security.access.vote.AuthenticatedVoter" />
40. <</span> beans:bean class = "com.piaoyi.common.security.DynamicRoleVoter" />
41. </</span> beans:list >
42. </</span> beans:property >
43. </</span> beans:bean >
44. </</span> beans:beans >
UserService.java
Java代码
1. public class UserService implements UserDetailsService{
2.
3. @Autowired
4. private ISystemUserService userService;
5. @Override
6. public UserDetails loadUserByUsername(String username)
7. throws UsernameNotFoundException {
8. // TODO Auto-generated method stub
9. SystemUser user = userService.findById(username);
10. if (user == null )
11. throw new UsernameNotFoundException( "The user name " + username
12. + " can not be found!" );
13.
14. List resultAuths = new ArrayList();
15. //增加access中配置的权限,实际上这里就是让所有登陆用户都具备该权限,
16. //而真正的资源权限验证留给AccessDecisionManager来决定
17. resultAuths.add(new GrantedAuthorityImpl( "HODLE" ));
18.
19. //验证用户名和密码是否正确,以及是否权限正确
20. return new User(username, user.getPassword().toLowerCase(), user.isStatus(), true ,
21. true , true , resultAuths);
22.
23.
24. }
25. }
DynamicRoleVoter.java
Java代码
1. public class DynamicRoleVoter implements
2. AccessDecisionVoter {
3.
4. @Autowired
5. private ISystemUserService userService;
6.
7. private PathMatcher pathMatcher = new AntPathMatcher();
8.
9. @SuppressWarnings ( "unchecked" )
10. public boolean supports(Class clazz) {
11. return true ;
12. }
13.
14.
15. public boolean supports(ConfigAttribute attribute) {
16. return true ;
17. }
18.
19.
20. public int vote(Authentication authentication, Object object,
21. java.util.Collection arg2) {
22. int result = ACCESS_ABSTAIN;
23. if (!(object instanceof FilterInvocation))
24. return result;
25. FilterInvocation invo = (FilterInvocation) object;
26. String url = invo.getRequestUrl();//当前请求的URL
27. Set authorities = null ;
28. String userId = authentication.getName();
29. //获得当前用户的可访问资源,自定义的查询方法,之后和当前请求资源进行匹配,成功则放行,否则拦截
30. authorities = loadUserAuthorities(userService.findById(userId));
31. Map> urlAuths = authService.getUrlAuthorities();
32. Set keySet = urlAuths.keySet();
33. for (String key : keySet) {
34. boolean matched = pathMatcher.match(key, url);
35. if (!matched)
36. continue ;
37. Set mappedAuths = urlAuths.get(key);
38. if (contain(authorities, mappedAuths)) {
39. result = ACCESS_GRANTED;
40. break ;
41. }
42. }
43. return result;
44. }
45.
46.
47. protected boolean contain(Set authorities,
48. Set mappedAuths) {
49. if (CollectionUtils.isEmpty(mappedAuths)
50. || CollectionUtils.isEmpty(authorities))
51. return false ;
52. for (GrantedAuthority item : authorities) {
53. if (mappedAuths.contains(item.getAuthority()))
54. return true ;
55. }
56. return false ;
57. }
58. }