将 Shiro 作为应用的权限基础 三:基于注解实现的授权认证过程

>>>>转载自:http://blog.csdn.net/tch918/article/details/13849325

授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。 

如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限等等。 

 

一、用户权限模型

为实现一个较为灵活的用户权限数据模型,通常把用户信息单独用一个实体表示,用户权限信息用两个实体表示。

  1. 用户信息用 LoginAccount 表示,最简单的用户信息可能只包含用户名 loginName 及密码 password 两个属性。实际应用中可能会包含用户是否被禁用,用户信息是否过期等信息。
  2. 用户权限信息用 Role 与 Permission 表示,Role 与 Permission 之间构成多对多关系。Permission 可以理解为对一个资源的操作,Role 可以简单理解为 Permission 的集合。
  3. 用户信息与 Role 之间构成多对多关系。表示同一个用户可以拥有多个 Role,一个 Role 可以被多个用户所拥有。

 


 

权限声明及粒度 

Shiro权限声明通常是使用以冒号分隔的表达式。就像前文所讲,一个权限表达式可以清晰的指定资源类型,允许的操作。同时,Shiro权限表达式支持简单的通配符,可以更加灵活的进行权限设置。 

下面以实例来说明权限表达式。 

可查询用户数据 

User:view 

可查询或编辑用户数据 

User:view,edit 

可对用户数据进行所有操作 

User:*或 user 

可编辑id为123的用户数据 

User:edit:123 

 

授权处理过程

认证通过后接受 Shiro 授权检查,授权验证时,需要判断当前角色是否拥有该权限。

只有授权通过,才可以访问受保护 URL 对应的资源,否则跳转到“未经授权页面”。

如果我们自定义Realm实现,比如我后面的例子中,自定义了ShiroDbRealm类,当访问被@RequiresPermissions注解的方法时,会先执行ShiroDbRealm.doGetAuthorizationInfo()进行授权。

@Controller  
@RequestMapping(value = "/user")  
public class UserController {  
   
@Resource(name="userService")  
private IUserService userService;  
   
/** 
 * 测试权限 
 * 只有拥有 user:create权限,才能进行注册 
 * @param user 
 * @return 
 */  
@RequestMapping(value = "/register")  
@ResponseBody  
@RequiresPermissions("user:create")  
public boolean register(User user){  
return userService.register(user);  
}
 

二、授权实现 

Shiro支持三种方式实现授权过程: 

  • 编码实现
  • 注解实现
  • JSP Taglig实现

 

1、基于编码的授权实现 

1、基于权限对象的实现 

创建org.apache.shiro.authz.Permission的实例,将该实例对象作为参数传递给Subject.isPermitted()进行验证。 

    Permission printPermission = new PrinterPermission("laserjet4400n", "print");    
    Subject currentUser = SecurityUtils.getSubject();    
    if (currentUser.isPermitted(printPermission)) {    
        //show the Print button    
    } else {    
        //don't show the button?  Grey it out?    
    }    


 

2基于字符串的实现 

相比笨重的基于对象的实现方式,基于字符串的实现便显得更加简洁。 

Subject currentUser = SecurityUtils.getSubject();    
if (currentUser.isPermitted("printer:print:laserjet4400n")) {    
    //show the Print button    
} else {    
    //don't show the button?  Grey it out?    
}  


使用冒号分隔的权限表达式是org.apache.shiro.authz.permission.WildcardPermission默认支持的实现方式。 

这里分别代表了资源类型:操作:资源ID 

 

2、基于注解的授权实现 

Shiro注解支持AspectJ、Spring、Google-Guice等,可根据应用进行不同的配置。 

 

相关的注解: 

@RequiresAuthentication 

可以用户类/属性/方法,用于表明当前用户需是经过认证的用户。  

        

@RequiresAuthentication    
public void updateAccount(Account userAccount) {    
    //this method will only be invoked by a     
    //Subject that is guaranteed authenticated    
    ...    
}  



@RequiresPermissions 

当前用户需拥有制定权限 

       

    @RequiresPermissions("account:create")    
    public void createAccount(Account account) {    
        //this method will only be invoked by a Subject    
        //that is permitted to create an account    
        ...    
    }   
 

 

3、基于JSP TAG的授权实现 

Shiro提供了一套JSP标签库来实现页面级的授权控制。 

在使用Shiro标签库前,首先需要在JSP引入shiro标签: 

    <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>  



hasRole标签 

验证当前用户是否属于该角色

    <shiro:hasRole name="administrator">    
        <a href="admin.jsp">Administer the system</a>    
    </shiro:hasRole>    


 

hasPermission标签 

验证当前用户是否拥有制定权限 

    <shiro:hasPermission name="user:create">    
        <a href="createUser.jsp">Create a new User</a>    
    </shiro:hasPermission>    

 

三、Shiro授权的内部处理机制 


 

1、在应用程序中调用授权验证方法(Subject的isPermitted*或hasRole*等) 

2、Sbuject会委托应用程序设置的securityManager实例调用相应的isPermitted*或hasRole*方法。 

3、接下来SecurityManager会委托内置的Authorizer的实例(默认是ModularRealmAuthorizer类的实例,类似认证实例)调用相应的授权方法。 

4、每一个Realm将检查是否实现了相同的Authorizer 接口。然后,将调用Reaml自己的相应的授权验证方法。 

 

四、授权代码

UserController:处理用户登录后的请求(注册)

    

    package org.shiro.demo.controller;  
      
    import javax.annotation.Resource;  
      
    import org.apache.shiro.authz.annotation.RequiresPermissions;  
    import org.apache.shiro.authz.annotation.RequiresRoles;  
    import org.shiro.demo.entity.User;  
    import org.shiro.demo.service.IUserService;  
    import org.springframework.stereotype.Controller;  
    import org.springframework.web.bind.annotation.RequestMapping;  
    import org.springframework.web.bind.annotation.ResponseBody;  
      
    @Controller  
    @RequestMapping(value = "/user")  
    public class UserController {  
          
        @Resource(name="userService")  
        private IUserService userService;  
      
        /** 
         * 测试权限 
         * 只有拥有 user:create 权限,才能进行注册 
         * @param user 
         * @return 
         */  
        @RequestMapping(value = "/register")  
        @ResponseBody  
        @RequiresPermissions("user:create")  
        public boolean register(User user){  
            return userService.register(user);  
        }  
          
        /** 
         * 测试角色 
         * 只有拥有 administrator 角色,才能跳转到register页面 
         * @return 
         */  
        @RequestMapping(value = "/toRegister")  
        @RequiresRoles("administrator")  
        public String toRegister(){  
            return "/system/user/register";  
        }  
    }  


 

ShiroDbRealm:自定义的指定Shiro验证用户授权的类

importjava.util.ArrayList;  
importjava.util.List;  
   
importjavax.annotation.Resource;  
   
importorg.apache.commons.lang.StringUtils;  
importorg.apache.shiro.authc.AuthenticationException;  
importorg.apache.shiro.authc.AuthenticationInfo;  
importorg.apache.shiro.authc.AuthenticationToken;  
importorg.apache.shiro.authc.SimpleAuthenticationInfo;  
importorg.apache.shiro.authc.UsernamePasswordToken;  
importorg.apache.shiro.authz.AuthorizationException;  
importorg.apache.shiro.authz.AuthorizationInfo;  
importorg.apache.shiro.authz.SimpleAuthorizationInfo;  
importorg.apache.shiro.realm.AuthorizingRealm;  
importorg.apache.shiro.subject.PrincipalCollection;  
importorg.shiro.demo.entity.Permission;  
importorg.shiro.demo.entity.Role;  
importorg.shiro.demo.entity.User;  
importorg.shiro.demo.service.IUserService;  
   
/** 
 * 自定义的指定Shiro验证用户登录的类 
 * @author TCH 
 * 
 */  
publicclass ShiroDbRealm extends AuthorizingRealm{  
   
//@Resource(name="userService")  
privateIUserService userService;  
   
publicvoid setUserService(IUserService userService) {  
this.userService= userService;  
}  
   
    /** 
     * 为当前登录的Subject授予角色和权限 
     * @see 经测试:本例中该方法的调用时机为需授权资源被访问时 
     * @see经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例未启用AuthorizationCache 
     * @seeweb层可以有shiro的缓存,dao层可以配有hibernate的缓存(后面介绍) 
     */  
protectedAuthorizationInfo doGetAuthorizationInfo(  
PrincipalCollectionprincipals) {  
   
//获取当前登录的用户名,等价于(String)principals.fromRealm(this.getName()).iterator().next()   
Stringaccount = (String) super.getAvailablePrincipal(principals);  
   
List<String>roles = new ArrayList<String>();   
List<String>permissions = new ArrayList<String>();  
   
//从数据库中获取当前登录用户的详细信息   
Useruser = userService.getByAccount(account);  
   
if(user!= null){  
//实体类User中包含有用户角色的实体类信息   
if(user.getRoles() != null && user.getRoles().size() > 0) {  
//获取当前登录用户的角色  
for(Role role : user.getRoles()) {  
roles.add(role.getName());  
 //实体类Role中包含有角色权限的实体类信息   
if(role.getPmss() != null && role.getPmss().size() > 0) {  
 //获取权限   
for(Permission pmss : role.getPmss()) {  
if(!StringUtils.isEmpty(pmss.getPermission())){  
permissions.add(pmss.getPermission());  
}  
}  
}  
}  
}  
}else{  
thrownew AuthorizationException();  
}  
   
//为当前用户设置角色和权限  
SimpleAuthorizationInfoinfo = new SimpleAuthorizationInfo();  
info.addRoles(roles);  
        info.addStringPermissions(permissions);  
         
returninfo;  
   
}  
   
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值