这里给出一个简单的安全验证的实现例子,先说一下需求:

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. }