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


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

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

     

    一、用户权限模型

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

    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类,当访问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标签: 


    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验证用户授权的类

    packageorg.shiro.demo.service.realm;
     
    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;
     
    }
     
    }

     

  • 相关阅读:
    MVC ORM 架构
    Kubernetes 第八章 Pod 控制器
    Kubernetes 第七章 Configure Liveness and Readiness Probes
    Kubernetes 第六章 pod 资源对象
    Kubernetes 第五章 YAML
    Kubernetes 核心组件
    Kubernetes 架构原理
    Kubernetes 第四章 kubectl
    Kubernetes 第三章 kubeadm
    yum 配置及yum 源配置
  • 原文地址:https://www.cnblogs.com/hanxue112253/p/3850546.html
Copyright © 2020-2023  润新知