美文网首页
shiro----shiro简单使用与源码分析(二)授权

shiro----shiro简单使用与源码分析(二)授权

作者: 不过意局bugyj | 来源:发表于2019-04-07 10:30 被阅读0次

上接一
隐式显式角色部分参考并截取了部分大佬


文章

授权

相关概念:

  • permission:权限,具体表明为能在什么资源中进行什么操作(不指定用户)。
  • roles:角色,权限的集合,可分为隐式角色与显式角色:
    • 隐式角色并不关心权限,仅仅关心角色本身,即用户有什么角色,然后再代码中判断用户有什么角色,然后再决定是否允许做什么操作。
    • 显式角色不仅指定了用户有什么角色,还明确定义了角色具有什么权限,然后再代码中判断有没有某权限即可。

显式角色的有点就是在代码中只需要判断是否有某一种权限即可,对某资源有某种操作这种东西是固定存在的,而角色可能有删除,有添加,每次删除或添加都得动源代码来增加或删除判断语句,后期维护需要很大的成本。做法就是这个博客中提到的:

隐式角色权限判断判断
显示角色权限判断

官方文档中建议:使用isPermitted或checkPermitted方法而不是使用hasRoles或checkRoles

often a better way of performing access control is through permission-based authorization.

和用户名密码一样,角色信息也来自于数据库或缓存中。然后AuthorizationInfo.addRole()加入到用户中。

检测权限

三种方式:

  • 代码方式,如使用if-else或者assert方式判断允许操作。
    如:
Subject currentUser = SecurityUtils.getSubject();

Permission p = new WildcardPermission("printer:print:laserjet4400n");

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

//guarantee that the current user is permitted
//to open a bank account:
Permission p = new AccountPermission("open");
currentUser.checkPermission(p);
openBankAccount();
//or
Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is permitted
//to open a bank account:
currentUser.checkPermission("account:open");
openBankAccount();
  • 注解方式,如在controller方法中注解所需要的角色或权限,eg.@RequiresRoles("admin")。
  • jsp/gsp标签库,直接在jsp文件中使用标签判断是否允许某个部件或数据的显示等,纯html可以在文件加载后ajax请求一次。

注意:注解方式不能和@Transaction重复使用,因为两个注解都是通过动态代理模式实现的,不能叠加动态代理。
示例代码:

 @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("do authorize");

//        1. 从principle中获取用户信息
        Object principle = principalCollection.getPrimaryPrincipal();
//        2. 利用登录用户信息老获取当前用户的角色和权限
        Set<String> roles = new HashSet<>();
        if ("root".equals(principle)) {
            roles.add("root");

        } else if ("admin".equals(principle)) {
            roles.add("admin");
        }
//        3. 构造AuthenticationInfo并设置其roles属性
        AuthorizationInfo info = new SimpleAuthorizationInfo(roles);
//        4. 返回
        return info;
    }

然后再配置两个controller方法:

    @RequestMapping(value = "/user/root")
    @RequiresRoles("root")
    @ResponseBody
    public String getRootPage() {
        sessionService.testSession();
        return "<h1>only root page</h1>";
    }

    @RequestMapping(value = "/user/admin")
    @RequiresRoles("admin")
    @ResponseBody
    public String getAdminPage() {
        sessionService.testSession();
        return "<h1>only admin page</h1>";
    }

最后为两个方法url设置拦截器:

/user/root=roles[root]
/user/admin=roles[admin]

可见在示例代码中root用户的角色名字因为root,admin的角色名也为admin,试验效果即root用户登录能访问/user/root,而不能访问/user/admin,会自动跳转到applicationContext文件中配置好的unauthorizedUrl页面显示权限不足。

流程分析

暂且使用这种权限验证方法测试下运行流程,:

  1. 在相应代码段打上断点,访问设置了权限拦截器的页面。
  2. 首先停留在了RolesAuthorizationFilter处,这就是我们前面在配置文件中配置的roles拦截器,它调用subject的hasAllRoles方法验证用户是否有相应角色。
  3. 进入subject的子类DelegatingSubject类中,可以看到subject如出一辙的使用了SecurityManager验证授权。
  4. 进入到SecurityManager的子类AuthorizingSecurityManager方法。调用自身属性authorizer验证。
  5. 之后也就和认证一样进入上一条说的authorizer对象的子类ModularRealmAuthorizer的hasAllRolers方法中:然后调用自身hasRole方法:

    到达我们熟悉的realm对象:
  6. 下一步还是先进入我们实现的realm的父类AuthorizingRealm的getAuthorizationInfo方法中,然后调用自身的模板方法doGetAuthorizationInfo,这才来到我们实现的MyRealm类中。



    获取权限信息,一层层返回给RolesAuthorizationFilter中验证。

同理:使用checkPermitted时就是以Subject的checkPermitted方法为入口,其他大致差不多。

修改成permission-based方式:

将配置修改

/user/root=perms[root:view]
/user/admin=perms[admin:view]

然后注解删除

//    @RequiresRoles("root")
//    @RequiresRoles("admin")

在MyRealm方法中设置表示权限的字符串(存储在数据库中):

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        if ("root".equals(principle)) {
            info.addStringPermission("root:*:*");
        } else if ("admin".equals(principle)) {
            info.addStringPermission("admin:*:*");
        }
        return info;

也可以封装权限字符串:

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        if ("root".equals(principle)) {
            Permission permission = new WildcardPermission("root:*:*")
            info.addObjectPermission(permission);
        } else if ("admin".equals(principle)) {
            Permission permission = new WildcardPermission("admin:*:*")
            info.addObjectPermission(permission);
        }
//        4. 返回
        return info;

然后访问即可



root身份登录,点击adminpege跳转到error.html文件中。



访问rootpage:

加密

相关文章

网友评论

      本文标题:shiro----shiro简单使用与源码分析(二)授权

      本文链接:https://www.haomeiwen.com/subject/ftydiqtx.html