spring security3教程系列--自定义权限管理

[plain]  view plain  copy
  1. 本文章摘编、转载需要注明来源 http://write.blog.csdn.net/postedit/8575062  


spring security3中的权限管理虽然有文件可配置,但是很多时候我们是需要数据库的支持,下面我演示下如何配置自定义权限管理,这个时候需要重新实现下面的类,

该文章适合对spring security3 有一定理解的人员


AccessDecisionManager是验证资源跟角色之间的关系,由于我个人不太喜欢用标签化,因为感觉灵活性不够好,所以我统一是用bean方式,至于用bean来描述是需要对security的

过滤链流程和各个属性依赖关系比较熟悉的了解才可以配置成功,这样灵活性大大加强

[java]  view plain  copy
  1. /** 
  2.  *  
  3.  * @author shadow 
  4.  * @email [email protected] 
  5.  * @create 2012.04.28 
  6.  */  
  7.   
  8. public class AccessDecisionManagerImpl implements AccessDecisionManager {  
  9.   
  10.     public void decide(Authentication authentication, Object object,  
  11.             Collection attributes)  
  12.             throws AccessDeniedException, InsufficientAuthenticationException {  
  13.         if (null == attributes)  
  14.             return;  
  15.         for (ConfigAttribute attribute : attributes) {  
  16.             String needRole = ((SecurityConfig) attribute).getAttribute();  
  17.             // authority为用户所被赋予的权限, needRole 为访问相应的资源应该具有的权限。  
  18.             for (GrantedAuthority grantedAuthority : authentication  
  19.                     .getAuthorities()) {  
  20.                 if (needRole.equals(grantedAuthority.getAuthority()))  
  21.                     return;  
  22.             }  
  23.         }  
  24.         throw new AccessDeniedException("权限不足!");  
  25.     }  
  26.   
  27.     public boolean supports(ConfigAttribute attribute) {  
  28.         return true;  
  29.     }  
  30.   
  31.     public boolean supports(Class clazz) {  
  32.         return true;  
  33.     }  
  34. }  



SecurityMetadataSource是角色跟资源加载器,项目启动的时候会先执行资源跟角色关联加载提供给security以便认证

[java]  view plain  copy
  1. /** 
  2.  * 初始化时加载角色资源关联数据 
  3.  *  
  4.  * @author shadow 
  5.  * @email [email protected] 
  6.  * @create 2012.04.28 
  7.  */  
  8. public class SecurityMetadataSourceExtendImpl implements  
  9.         SecurityMetadataSourceExtend {  
  10.   
  11.     private boolean expire = false// 过期标识  
  12.   
  13.     private RoleService roleService; // 角色服务类  
  14.   
  15.     private ResourceService resourceService; // 资源服务类  
  16.   
  17.     private RequestMatcher requestMatcher; // 匹配规则  
  18.   
  19.     private String matcher; // 规则标识  
  20.   
  21.     private Map> kv = new HashMap>(); // 资源集合  
  22.   
  23.     public RoleService getRoleService() {  
  24.         return roleService;  
  25.     }  
  26.   
  27.     @javax.annotation.Resource  
  28.     public void setRoleService(RoleService roleService) {  
  29.         this.roleService = roleService;  
  30.     }  
  31.   
  32.     public ResourceService getResourceService() {  
  33.         return resourceService;  
  34.     }  
  35.   
  36.     @javax.annotation.Resource  
  37.     public void setResourceService(ResourceService resourceService) {  
  38.         this.resourceService = resourceService;  
  39.     }  
  40.   
  41.     public boolean supports(Class clazz) {  
  42.         return true;  
  43.     }  
  44.   
  45.     // 初始化方法时候从数据库中读取资源  
  46.     // @PostConstruct  
  47.     public void init() {  
  48.         load();  
  49.     }  
  50.   
  51.     public Collection getAllConfigAttributes() {  
  52.         Set attributes = new HashSet();  
  53.         for (Map.Entry> entry : kv  
  54.                 .entrySet()) {  
  55.             attributes.addAll(entry.getValue());  
  56.         }  
  57.         return attributes;  
  58.     }  
  59.   
  60.     public Collection getAttributes(Object object)  
  61.             throws IllegalArgumentException {  
  62.         HttpServletRequest request = ((FilterInvocation) object).getRequest();  
  63.         // System.out.println("requestUrl is " + request.getRequestURI());  
  64.   
  65.         // 检测是否刷新了资源  
  66.         if (isExpire()) {  
  67.             // 清空原本资源  
  68.             kv.clear();  
  69.             expire = false;  
  70.         }  
  71.   
  72.         // 如果资源Map为空的时候则重新加载一次  
  73.         if (null == kv || kv.isEmpty())  
  74.             load();  
  75.   
  76.         // 检测请求与当前资源匹配的正确性  
  77.         Iterator iterator = kv.keySet().iterator();  
  78.         while (iterator.hasNext()) {  
  79.             String uri = iterator.next();  
  80.             if (matcher.toLowerCase().equals("ant")) {  
  81.                 requestMatcher = new AntPathRequestMatcher(uri);  
  82.             }  
  83.             if (matcher.toLowerCase().equals("regex")) {  
  84.                 requestMatcher = new RegexRequestMatcher(uri, request  
  85.                         .getMethod(), true);  
  86.             }  
  87.             if (requestMatcher.matches(request))  
  88.                 return kv.get(uri);  
  89.         }  
  90.         return null;  
  91.     }  
  92.   
  93.     /** 
  94.      * 加载所有资源与权限的关系 
  95.      */  
  96.     public void load() {  
  97.         List resources = this.resourceService.loadForAll();  
  98.         for (Resource resource : resources) {  
  99.             List roles = this.roleService.findByResourceId(resource  
  100.                     .getId());  
  101.             kv.put(resource.getContent(), list2Collection(roles));  
  102.         }  
  103.     }  
  104.   
  105.     /** 
  106.      * 将List集合转换为框架需要的Collection集合 
  107.      *  
  108.      * @param roles 
  109.      * @return Collection 
  110.      */  
  111.     private Collection list2Collection(List roles) {  
  112.         List list = new ArrayList();  
  113.         for (Role role : roles)  
  114.             list.add(new SecurityConfig(role.getName()));  
  115.         return list;  
  116.     }  
  117.   
  118.     public void setMatcher(String matcher) {  
  119.         this.matcher = matcher;  
  120.     }  
  121.   
  122.     public boolean isExpire() {  
  123.         return expire;  
  124.     }  
  125.   
  126.     public void expireNow() {  
  127.         this.expire = true;  
  128.     }  
  129.   
  130. }  


FilterSecurityInterceptor是资源访问第一个需要经过的过滤器,这个类我们还是不需要重写了,直接使用spring security提供的比较

具体路径org.springframework.security.web.access.intercept.FilterSecurityInterceptor


UserDetailsService这个类security的form表单登录处理

[java]  view plain  copy
  1. /** 
  2.  * SPRING SECURITY3用户登录处理 
  3.  *  
  4.  * @author shadow 
  5.  * @email [email protected] 
  6.  * @create 2012.04.28 
  7.  */  
  8. public class UserDetailsServiceImpl implements UserDetailsService {  
  9.   
  10.     private UserService userService;  
  11.     private RoleService roleService;  
  12.   
  13.     public UserService getUserService() {  
  14.         return userService;  
  15.     }  
  16.   
  17.     @Resource  
  18.     public void setUserService(UserService userService) {  
  19.         this.userService = userService;  
  20.     }  
  21.   
  22.     public RoleService getRoleService() {  
  23.         return roleService;  
  24.     }  
  25.   
  26.     @Resource  
  27.     public void setRoleService(RoleService roleService) {  
  28.         this.roleService = roleService;  
  29.     }  
  30.   
  31.     public UserDetails loadUserByUsername(String username)  
  32.             throws UsernameNotFoundException {  
  33.   
  34.         // 使用User服务类查询数据用户是否存在,如不存在或密码错误则抛出对应的异常  
  35.         List users = this.userService.findByUserName(username);  
  36.   
  37.         if (null == users || users.isEmpty())  
  38.             throw new UsernameNotFoundException("用户/密码错误,请重新输入!");  
  39.   
  40.         User user = users.get(0);  
  41.         List roles = this.roleService.findByUserId(user.getId());  
  42.         if (null == roles || roles.isEmpty())  
  43.             throw new UsernameNotFoundException("权限不足!");  
  44.         // 把权限赋值给当前对象  
  45.         Collection gaRoles = new ArrayList();  
  46.         for (Role role : roles) {  
  47.             gaRoles.add(new SimpleGrantedAuthority(role.getName()));  
  48.         }  
  49.         user.setAuthorities(gaRoles);  
  50.         return user;  
  51.     }  
  52.   
  53. }  



三个类都准备好了现在去配置xml文件,先声明三个类的bean

[java]  view plain  copy
  1.          
  2. "userDetailsService"  
  3.     class="com.shadow.security.service.UserDetailsServiceImpl" />  
  4.   
  5.   
  6. "accessDecisionManager"  
  7.     class="com.shadow.security.service.AccessDecisionManagerImpl" />  
  8.   
  9.   
  10. "securityMetadataSource"  
  11.     class="com.shadow.security.service.SecurityMetadataSourceExtendImpl">  
  12.     "matcher" value="ant" />  
  13.   



然后配置filterSecurityInterceptor,我们不再用security提供的实现类,而是使用我们刚刚写的实现类


[java]  view plain  copy
  1.   
  2.     "filterSecurityInterceptor"  
  3.         class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">  
  4.         "authenticationManager"  
  5.             ref="authenticationManager" />  
  6.         "accessDecisionManager"  
  7.             ref="accessDecisionManager" />  
  8.         "securityMetadataSource"  
  9.             ref="securityMetadataSource" />  
  10.       


至于authenticationManager的注入如下(rememberMeAuthenticationProvider可不注入,这个东西是记住密码功能需要用到的玩意)


[java]  view plain  copy
  1.   
  2.     "authenticationManager"  
  3.         class="org.springframework.security.authentication.ProviderManager">  
  4.         "providers">  
  5.               
  6.                 "daoAuthenticationProvider" />  
  7.                 "rememberMeAuthenticationProvider" />  
  8.               
  9.           
  10.       
  11.   
  12.       
  13.     "daoAuthenticationProvider"  
  14.         class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">  
  15.         "hideUserNotFoundExceptions" value="false"/>  
  16.         "userDetailsService" ref="userDetailsService" />  
  17.         "passwordEncoder" ref="passwordEncoder" />  
  18.         "saltSource" ref="saltSource" />  
  19.       
  20.   
  21.       
  22.     "passwordEncoder"  
  23.         class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />  
  24.   
  25.       
  26.     "saltSource"  
  27.         class="org.springframework.security.authentication.dao.ReflectionSaltSource">  
  28.         "userPropertyToUse" value="username" />  
  29.       



然后配置我们的过滤链

[java]  view plain  copy
  1.   
  2.     "securityFilterChainProxy"  
  3.         class="org.springframework.security.web.FilterChainProxy">  
  4.           
  5.               
  6.                 "/services/**"  
  7.                     filters="none" />  
  8.                 "/test*" filters="none" />  
  9.                 "/**"  
  10.                     filters="concurrentSessionFilter,securityContextPersistenceFilter,logoutFilter,usernamePasswordAuthenticationFilter,rememberMeAuthenticationFilter,sessionManagementFilter,anonymousAuthFilter,exceptionTranslationFilter,filterSecurityInterceptor" />  
  11.               
  12.           
  13.       



至于过滤链里的其他filter我就不一一列出来了,然后大概流程就这样可以了,然后页面就搞个普通的security表单,提交的时候会进入到我们的userDetailsService实现类里验证你输入的账号密码是否一致,至于主要三个model就不出代码了,相信大家也应该明白,就是User,Role,Resource三者之间的关联

你可能感兴趣的:(spring)