授权即访问控制,它将判断用户在应用程序中对资源是否拥有相应的访问权限。 如,判断一个用户有查看页面的权限,编辑数据的权限,拥有某一按钮的权限等等。 
一、用户权限模型
为实现一个较为灵活的用户权限数据模型,通常把用户信息单独用一个实体表示,用户权限信息用两个实体表示。
用户信息用 LoginAccount 表示,最简单的用户信息可能只包含用户名 loginName 及密码 password 两个属性。实际应用中可能会包含用户是否被禁用,用户信息是否过期等信息。
用户权限信息用 Role Permission 表示,Role Permission 之间构成多对多关系。Permission 可以理解为对一个资源的操作,Role 可以简单理解为 Permission 的集合。
用户信息与 Role 之间构成多对多关系。表示同一个用户可以拥有多个 Role,一个 Role 可以被多个用户所拥有。
权限声明及粒度 
Shiro权限声明通常是使用以冒号分隔的表达式。就像前文所讲,一个权限表达式可以清晰的指定资源类型,允许的操作。同时,Shiro权限表达式支持简单的通配符,可以更加灵活的进行权限设置。 下面以实例来说明权限表达式。 
可查询用户数据 
User:view 
可查询或编辑用户数据 
User:view,edit 
可对用户数据进行所有操作 
User:* user 
可编辑id123的用户数据 
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支持三种方式实现授权过程: 
o 编码实现
o 注解实现
o JSP Taglig实现
1、基于编码的授权实现 
1、基于权限对象的实现 
创建org.apache.shiro.authz.Permission的实例,将该实例对象作为参数传递给Subject.isPermitted()进行验证。
    Permission printPermission =
new PrinterPermission("laserjet4400n", "print"); 
    Subject currentUser = Subject(); 
    if (currentUser.isPermitted(printPermission)) { 
        //show the Print button 
    } else
        //don't show the button?  Grey it out? 
    } 
2、基于字符串的实现 
相比笨重的基于对象的实现方式,基于字符串的实现便显得更加简洁。 
    Subject currentUser = Subject();
    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注解支持AspectJSpringGoogle-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="/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、在应用程序中调用授权验证方法(SubjectisPermitted*hasRole*
2Sbuject会委托应用程序设置的securityManager实例调用相应的isPermitted*hasRole*方法。 
3、接下来SecurityManager会委托内置的Authorizer的实例(默认是ModularRealmAuthorizer类的实例,类似认证实例)调用相应的授权方法。 
4、每一个Realm将检查是否实现了相同的Authorizer 接口。然后,将调用Reaml自己的相应的授权验证方法。
四、授权代码
UserController:处理用户登录后的请求(注册)
package org.ller;
import javax.annotation.Resource;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.shiro.ity.User;
import org.shiro.demo.service.IUserService;
@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验证用户授权的类
package org.shiro.alm;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.apachemons.lang.StringUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.alm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.shiro.ity.Permission;
import org.shiro.ity.Role;
import org.shiro.ity.User;
import org.shiro.demo.service.IUserService;
/**
* 自定义的指定Shiro验证用户登录的类
* @author TCH
*
*/
public class ShiroDbRealm extends AuthorizingRealm{
    //@Resource(name="userService")
    private IUserService userService;
    public void setUserService(IUserService userService) {
        this.userService= userService;
    }
    /**
    * 为当前登录的Subject授予角和权限
    * @see 经测试:本例中该方法的调用时机为需授权资源被访问时
    * @see经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,
* 这表明本例未启用AuthorizationCache
    * @seeweb层可以有shiro的缓存dao层可以配有hibernate的缓存(后面介绍)
    */
    protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
        //获取当前登录的用户名,等价于(String)
//principals.Name()).iterator().next()
        String account = (String)
super.getAvailablePrincipal(principals);
        List<String> roles = new ArrayList<String>();
        List<String> permissions = shiro权限控制new ArrayList<String>();
        //从数据库中获取当前登录用户的详细信息
        User user = userService.getByAccount(account);
        if(user!= null){
            //实体类User中包含有用户角的实体类信息
            if(Roles() != null && Roles().size() > 0) {
                //获取当前登录用户的角
                for(Role role : Roles()) {
                    roles.Name());
                    //实体类Role中包含有角权限的实体类信息
                    if(Pmss() != null &&
Pmss().size() > 0) {
                        //获取权限
                        for(Permission pmss : Pmss()) {
                                if(!StringUtils.isEmpty(Permission())){
                                permissions.Permission());
                            }
                        }
                    }
                }
            }
        }else{
            throw new AuthorizationException();
        }
   
        //为当前用户设置角和权限
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(roles);
        info.addStringPermissions(permissions);
        return info;
    }
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。