实战-Shiro安全框架(二)权限控制

  上一篇讲解了shiro的认证流程以及实现。这一篇,笔者要详细讲解shiro的另一重要部分就是权限控制,简称授权。

  授权流程跟认证流程很相似,大致过程为当前用户subject调用isPermitted*/hasRole* 接口时,将会委派给security manager,security manager委派给Authorizer(授权器)。比如调用的是isPermitted("user:create"),其中PermissionResolver 把字符串转换成相应的 Permission 实例。在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角色/权限用于匹配传入的角色/权限;Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果有多个Realm,会委托给 ModularRealmAuthorizer 进行循环判断, 如果匹配如 isPermitted*/hasRole* 会返回true,否则返回false表示授权失败。

   Shiro支持三种授权方式,分别如下:

   编程式:通过写if/else 授权代码块完成 (不推荐

   注解式:通过在执行的Java方法上放置相应的注解完成,没有权限将抛出相 应的异常 (需要在springmvgc配置文件加一段配置才能注解生效

<!--
   4. 配置 LifecycleBeanPostProcessor. 可以自定的来调用配置在 Spring IOC 容器中 shiro bean 的生命周期方法.
   -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

	<!-- Enable Shiro Annotations for Spring-configured beans.  Only run after
         the lifecycleBeanProcessor has run: -->
	<!--
    5. 启用 IOC 容器中使用 shiro 的注解. 但必须在配置了 LifecycleBeanPostProcessor 之后才可以使用.
    -->
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
		  depends-on="lifecycleBeanPostProcessor">
		<property name="proxyTargetClass" value="true" />
	</bean>
	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager"/>
	</bean>

   JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成(需要引入标签库<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>   )

例如

<shiro:principal></shiro:principal>
	
<shiro:hasRole name="admin">

   shiro的权限规则

规则:资源标识符:操作:对象实例 ID 。 即对哪个资源的哪个 实例可以进行什么操作.。其默认支持通配符权限字符串,: 表 示资源/操作/实例的分割;, 表示操作的分割,* 表示任意资 源/操作/实例。例如:user:create  表示可以拥有对user模块(领域)进行新增操作的权限。

接下来进行具体演示,准备好数据表

1.用户表

2.角色表

3.权限表

4.用户-角色表

5.角色-权限表

 

6.service接口

实际开发中,我们常常将用户按角色来划分,不同角色拥有不同权限,而不是直接按用户具有哪些权限来操作。

现在开始编码实现,实现realm中的授权方法,具体如下

 @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取唯一标识principal
        String principal = (String) principalCollection.getPrimaryPrincipal();
//从数据库获取用户的具体权限信息
        Set<String> permissions = userService.getPermissions(principal);
//从数据库获取用户的具体角色信息
        Set<String> roles = userService.getRoles(principal);
//创建具有permissions、roles信息的SimpleAuthorizationInfo返回
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
        info.setStringPermissions(permissions);
        return info;
    }

UserServcie接口方法的具体实现如下

@Override
    public Set<String> getRoles(String loginName) {
        SysUser user = getUserByLoginNmae(loginName);
        SysUserRoleExample userRoleExample = new SysUserRoleExample();
        userRoleExample.createCriteria().andUserCodeEqualTo(user.getUserCode());
        List<SysUserRole> rolesCode = userRoleMapper.selectByExample(userRoleExample);
        Set<String> roles = new HashSet<>();
        SysRoleExample roleExample = new SysRoleExample();
        for (SysUserRole userRole : rolesCode) {
            roleExample.clear();
            roleExample.createCriteria().andRoleCodeEqualTo(userRole.getRoleCode());
            List<SysRole> roles1 = roleMapper.selectByExample(roleExample);
            for (SysRole role : roles1) {
                roles.add(role.getRoleCode());
            }
        }
        return roles;
    }
@Override
    public Set<String> getPermissions(String loginName) {
        Set<String> permissions = new HashSet<>();
        Set<String> roles = getRoles(loginName);
        SysRolePermissionExample example = new SysRolePermissionExample();
        for (String role : roles) {
            example.clear();
            example.createCriteria().andRoleCodeEqualTo(role);
            List<SysRolePermission> rolePermissions = rolePermissionMapper.selectByExample(example);
            for (SysRolePermission permission : rolePermissions) {
                permissions.add(permission.getPermissionCode());
            }
        }
        return permissions;
    }
@Override
    public SysUser getUserByLoginNmae(String loginName) {
        SysUserExample example = new SysUserExample();
        example.createCriteria().andLoginNameEqualTo(loginName);
        List<SysUser> users = userMapper.selectByExample(example);
        return users.get(0);
    }

这代码还没有优化,有点又臭又长。。。

这里要补充一点就是,在shiro认证的时候,在realm里就会把先认证和后授权一次性执行完毕,也就是说,在登陆成功后,该用户的角色和权限信息就已经得到并保存起来了,而不是认证的时候就只执行doGetAuthenticationInfo,授权的时候就再跳到realm只执行doGetAuthorizationInfo。这也很符合逻辑。在接下来的一些权限访问控制时,就会取出来进行匹配。

后台controller代码如下

    //只有admin角色才能行执行controller
    @RequiresRoles(value = {"admin"})
   //只有具有"user:delete"权限才能执行此controller
    @RequiresPermissions({"user:delete"})
    @RequestMapping("/UserCreate.action")
    public String userCreate(){
        Subject subject = SecurityUtils.getSubject();
    //用户已经认证过
        if (subject.isAuthenticated()){
            if (subject.isPermitted("user:delete")) System.out.println("拥有创建用户权限!!!");
            if (subject.hasRole("admin")) System.out.println("拥有角色");
            userService.createUser(new SysUser());
            System.out.println("controller创建user");
        }
        return "list";
    }

注意:要想在springmvc让shiro的注解生效,必须在spring的配置文件配置让注解生效的配置

笔者试了一下,在service层加注解,注解会失效,因为配置了spring的事务管理的原因,让shiro注解失效了,所以最好就是加在controller里,也比较符合我们的实际开发。

如果没有权限或者角色访问的话,shiro会报错,如下所示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啊杰eboy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值