权限控制框架Spring Security 和Shiro 的总结

关于权限控制,一开始感觉比较难,后来先是接触了Spring Security 学起来也比较吃力,再是学习了Shiro,感觉简单很多。

总体来说这些框架,主要做了两个事情

Authentication身份认证/登录,验证用户是不是拥有相应的身份;

Authorization授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;

  还做了一些事情,我也没有深入,主要就这么。

 从以下配置文件可以看出。

    <beans:bean id="myFilter" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">

         < beans:property  name ="authenticationManager"  ref ="autheticationManager" ></ beans:property >
         < beans:property  name ="accessDecisionManager"   >
             < beans:bean  class ="org.springframework.security.access.vote.AffirmativeBased" >
                 < beans:property  name ="decisionVoters" >
                     < beans:list >
                         < beans:bean  class ="org.springframework.security.access.vote.RoleVoter"   />
                         < beans:bean  class ="org.springframework.security.access.vote.AuthenticatedVoter"   />
                     </ beans:list >
                 </ beans:property >
             </ beans:bean >
         </ beans:property >
         <!--  resourceService在applicationContext*.xml中或注解定义  -->
         < beans:property  name ="securityMetadataSource"  ref ="securityMetadataSource"   />
     </ beans:bean >

      这里有一个authenticationManager是做身份认证的,有一个accessDecisionManager是做授权管理的。还有一个是securityMetadataSource这里主要做的从数据库取出资源与角色的关系,为第二个授权做准备,授权又是根据用户的身份找出他的角色,根据角色判断是否有访问资源的权限。

 先介绍这个 securityMetadataSource这里需要实现FilterInvocationSecurityMetadataSource接口,大致如下:

 /**

     * resourceMa
     * resourceMap 存储的资源为<Url,Collection<ConfigAttribute>>,其中Collection<ConfigAttribute>为资源对应的角色集合,其构造方式为new SecurityConfig("ROLE_" + role.getRoleId().toString())
     * resourceMap 里面存储的内容为<1个URL,对应得角色的集合>
     * 加载所有的资源与角色的关系
     
*/
     public  void init()  throws Exception {
        resourceMap =  new HashMap<String,Collection<ConfigAttribute>>();
        List<Resource> resources = resourceDao.findAll();
        
         for(Resource item:resources) {
        String url = item.getUrlpath();
             if(url !=  null) {
                 List<Role> roles = roleDao.getRolesByResourceId(item.getResourceid());
                 if(roles != null && roles.size()>0) {
                     if(resourceMap.containsKey(item.getUrlpath())) {
                        Collection<ConfigAttribute> old = resourceMap.get(item.getUrlpath());
                        old.addAll(listToCollection(roles));
                    }  else {
                        resourceMap.put(url, listToCollection(roles));
                    }
                }
            }
        }
    }
    
     /**
     * 将角色转化为ConfigAttribute
     * 
@param  roles
     * 
@return
     
*/
     private Collection<ConfigAttribute> listToCollection(Collection<Role> roles) {
        Collection<ConfigAttribute> list =  new ArrayList<ConfigAttribute>();
         for(Role role :roles) {
            ConfigAttribute configAttribute =  new SecurityConfig("ROLE_"+role.getRoleid().toString());
             // list.add(new SecurityConfig("ROLE_" + role.getRoleid().toString()));
            list.add(configAttribute);
        }
         return list;
        
    }

     /**
     * 将资源与权限的对应关系Map转化为Security需要的Collection
     
*/
    @Override
     public Collection<ConfigAttribute> getAllConfigAttributes() {
        Set<ConfigAttribute> allAttributes =  new HashSet<ConfigAttribute>();
         for(Map.Entry<String, Collection<ConfigAttribute>>  entry:resourceMap.entrySet()) {
            allAttributes.addAll(entry.getValue());
        }
         return allAttributes;
    }

  //返回所请求资源所需要的权限  

public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {

String requestUrl = ((FilterInvocation) object).getRequestUrl();

System.out.println("requestUrl is " + requestUrl);

if(resourceMap == null) {

try { init(); }

catch (Exception e)

{ e.printStackTrace(); } }

return resourceMap.get(requestUrl);

}

 

  上面前几个方法是在程序启动的时候执行,最后一个方法是在你要访问某个资源的时候自动调用的最终返回的是 Collection<ConfigAttribute>  权限集合。

accessDecisionManager授权管理,根据上面返回的权限集合,和用户登录存储的用户权限进行对比判断用户是否有访问权限,自己写授权管理的话需要实现AccessDecisionManager 接口,如下:

public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {

         if(configAttributes ==  null) {
             return;
        }
         // 所请求的资源拥有的权限(一个资源对多个权限)
        Iterator<ConfigAttribute> iterator = configAttributes.iterator();
         while(iterator.hasNext()) {
            ConfigAttribute configAttribute = iterator.next();
             // 访问所请求资源所需要的权限
            String needPermission = configAttribute.getAttribute();
            System.out.println("needPermission is " + needPermission);
             // 用户所拥有的权限authentication
             for(GrantedAuthority ga : authentication.getAuthorities()) {
                 if(needPermission.equals(ga.getAuthority())) {
                     return;
                }
            }
        }
         // 没有权限让我们去捕捉
         throw  new AccessDeniedException(" 没有权限访问!");

    } 

authenticationManager身份认证,主要包含登陆这些,框架一般会给我们提供form表单提交的处理接口,我们需要实现接口和配置一些相关配置。

 <http auto-config="true" access-denied-page="/accessDenied.jsp" use-expressions="true">

         < form-login  login-page ="/index.jsp"  login-processing-url ="/j_spring_security_check"
        always-use-default-target
="true"  authentication-failure-url ="/index.jsp?login_error=true"
        default-target-url
="/frame.jsp"
        
/>
                
         < logout  logout-success-url ="/index.jsp" />
         < intercept-url  pattern ="/style/**"  filters ="none"   />
         < intercept-url  pattern ="/js/**"  filters ="none"   />
          < intercept-url  pattern ="/index.jsp"  filters ="none"   />
         < intercept-url  pattern ="/login.action"  filters ="none" />
         < intercept-url  pattern ="/frame.jsp"  access ="isAuthenticated()" />
         < anonymous  />
         < session-management  invalid-session-url ="/accessDenied.jsp" >
             < concurrency-control  max-sessions ="1"  error-if-maximum-exceeded ="true"   />
         </ session-management >
         <!--  将自己的过滤器加入到过滤器链中, 放在FILTER_SECURITY_INTERCEPTOR之前 -->
         < custom-filter  ref ="myFilter"  before ="FILTER_SECURITY_INTERCEPTOR" />
     </ http >
    
     < authentication-manager  alias ="autheticationManager" >
         <!--  使用自定义UserDetailsService  -->
         < authentication-provider  user-service-ref ="userService" />

    </authentication-manager> 

 以上是Spring Security的配置,还需要在userService 登录验证里面实现UserDetailsService 接口。Shiro实现方式如下 :

    Subject currentUser = SecurityUtils.getSubject();

        System.out.println(EncryptUtils.encryptMD5(user.getPassword()));
        UsernamePasswordToken token =  new UsernamePasswordToken(
                user.getUsercode(), EncryptUtils.encryptMD5(user.getPassword()));
        token.setRememberMe( true);
         try {
            currentUser.login(token);
        }  catch (AuthenticationException e) {
            modelView.addObject("message", "login errors");
            modelView.setViewName("/login");
            e.printStackTrace();
            

        } 

   accessDecisionManager

 

 

转载于:https://www.cnblogs.com/brucetie/p/4136990.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值