设为首页 收藏本站
查看: 1760|回复: 0

[经验分享] Apache Shiro学习笔记(三)用户授权简单示例

[复制链接]

尚未签到

发表于 2018-11-19 12:57:49 | 显示全部楼层 |阅读模式
鲁春利的工作笔记,好记性不如烂笔头
  

  Shiro默认提供的Realm
DSC0000.jpg

  认证(Authentication)用来证明用户身份是合法的;而授权(Authorize)用来控制合法用户能够做什么(能访问哪些资源)。
  

  实际系统应用中一般继承AuthorizingRealm(授权)即可;其继承了AuthenticatingRealm(即身份验证),而且也间接继承了CachingRealm(带有缓存实现)。

  

  在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。
  

  Shiro的ini配置文件(shiro-authorize-permission.ini)
[main]
# 定义变量
# 变量名=全类名
[users]
# 用户名=密码,角色1,角色2,...,角色N
lucl=123,role1,role2
zs=123,role1
[roles]
# 角色=权限1,权限2,...,权限N
role1=user:create,user:update
role2=user:create,user:delete  

  基于角色的访问控制
/**
* 基于角色的访问控制
*/
@Test
public void testWhetherHasRole () {
    // 1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
    Factory factory = new IniSecurityManagerFactory("classpath:shiro/authorize/shiro-authorize-permission.ini");
    // 2、得到SecurityManager实例并绑定给SecurityUtils
    org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
    SecurityUtils.setSecurityManager(securityManager);
    // 3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
    Subject subject = SecurityUtils.getSubject();
    UsernamePasswordToken token = new UsernamePasswordToken("lucl", "123");
    try{
        // 4、登录,即身份验证
        subject.login(token);
    } catch (AuthenticationException e) {
        // 5、身份验证失败
        logger.info("用户身份验证失败");
        e.printStackTrace();
    }
    // 用户身份得到确认
    if (subject.isAuthenticated()) {
        logger.info("用户登录成功。");
        /**
         * 进行权限判断
         */
        // 判断拥有角色:role1
        Assert.assertTrue(subject.hasRole("role1"));
        // 判断拥有角色:role1 and role2
        Assert.assertTrue(subject.hasAllRoles(Arrays.asList("role1", "role2")));
        // 判断拥有角色:role1 and role2 and !role3
        boolean[] result = subject.hasRoles(Arrays.asList("role1", "role2", "role3"));
        Assert.assertEquals(true, result[0]);
        Assert.assertEquals(true, result[1]);
        Assert.assertEquals(false, result[2]);
        // Shiro 提供了hasRole/hasRole 用于判断用户是否拥有某个角色/某些权限;
        // 但是没有提供如hashAnyRole用于判断是否有某些权限中的某一个。
        // 断言拥有角色:role1
        subject.checkRole("role1");
        // 断言拥有角色:role1 and role3 失败抛出异常
        subject.checkRoles("role1", "role3");
    } else {
        logger.info("用户登录失败。");
    }
    // 6、退出
    subject.logout();
}  

  基于资源的访问控制
/**
* 基于资源的访问控制
*/
@Test
public void testWhetherHasPermission () {
    // 1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
    Factory factory = new IniSecurityManagerFactory("classpath:shiro/authorize/shiro-authorize-permission.ini");
    // 2、得到SecurityManager实例并绑定给SecurityUtils
    org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
    SecurityUtils.setSecurityManager(securityManager);
    // 3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
    Subject subject = SecurityUtils.getSubject();
    UsernamePasswordToken token = new UsernamePasswordToken("lucl", "123");
    try{
        // 4、登录,即身份验证
        subject.login(token);
    } catch (AuthenticationException e) {
        // 5、身份验证失败
        logger.info("用户身份验证失败");
        e.printStackTrace();
    }
    // 用户身份得到确认
    if (subject.isAuthenticated()) {
        logger.info("用户登录成功。");
        /**
         * 进行权限判断
         */
        // 判断拥有权限:user:create
        Assert.assertTrue(subject.isPermitted("user:create"));
        // 判断拥有权限:user:update and user:delete
        Assert.assertTrue(subject.isPermittedAll("user:update", "user:delete"));
        // 判断没有权限:user:view
        Assert.assertFalse(subject.isPermitted("user:view"));
        // 断言拥有权限:user:create
        subject.checkPermission("user:create");
        // 断言拥有权限:user:delete and user:update
        subject.checkPermissions("user:delete", "user:update");
        // 断言拥有权限:user:view 失败抛出异常
        subject.checkPermissions("user:view");
    } else {
        logger.info("用户登录失败。");
    }
    // 6、退出
    subject.logout();
}  

  org.apache.shiro.authz.Permission
package org.apache.shiro.authz;
/**
* A Permission represents the ability to perform an action or access a resource.  
*
* @see org.apache.shiro.authz.permission.WildcardPermission WildcardPermission
* @since 0.2
*/
public interface Permission {
    /**
     * Returns true if this current instance implies all the functionality and/or
     * resource access described by the specified Permission argument, false otherwise.
     * If "permission1 implies permission2", i.e. permission1.implies(permission2) ,
     * then any Subject granted permission1 would have ability greater than or equal to that defined by permission2..
     *
     * @param p the permission to check for behavior/functionality comparison.
     * @return
     *
     * 用汉语翻译的意思就是当前调用implies的Permission的实现要比Permission功能强大,最起码不能更低。
     *
     */
    boolean implies(Permission p);
}  

  org.apache.shiro.authz.permission.WildcardPermission
package org.apache.shiro.authz.permission;
/**
*
* @since 0.9
*/
public class WildcardPermission implements Permission, Serializable {
    /*--------------------------------------------
    |             C O N S T A N T S             |
    ============================================*/
    protected static final String WILDCARD_TOKEN = "*";
    protected static final String PART_DIVIDER_TOKEN = ":";
    protected static final String SUBPART_DIVIDER_TOKEN = ",";
    protected static final boolean DEFAULT_CASE_SENSITIVE = false;
    protected WildcardPermission() {
    }
    public WildcardPermission(String wildcardString) {
        this(wildcardString, DEFAULT_CASE_SENSITIVE);
    }
    public WildcardPermission(String wildcardString, boolean caseSensitive) {
        setParts(wildcardString, caseSensitive);
    }
    protected void setParts(String wildcardString) {
        setParts(wildcardString, DEFAULT_CASE_SENSITIVE);
    }
    public boolean implies(Permission p) {
        // By default only supports comparisons with other WildcardPermissions
        if (!(p instanceof WildcardPermission)) {
            return false;
        }
        WildcardPermission wp = (WildcardPermission) p;
        List otherParts = wp.getParts();
        int i = 0;
        for (Set otherPart : otherParts) {
            // If this permission has less parts than the other permission, everything after the number of parts contained
            // in this permission is automatically implied, so return true
            if (getParts().size() - 1 < i) {
                return true;
            } else {
                Set part = getParts().get(i);
                if (!part.contains(WILDCARD_TOKEN) && !part.containsAll(otherPart)) {
                    return false;
                }
                i++;
            }
        }
        // If this permission has more parts than the other parts, only imply it if all of the other parts are wildcards
        for (; i < getParts().size(); i++) {
            Set part = getParts().get(i);
            if (!part.contains(WILDCARD_TOKEN)) {
                return false;
            }
        }
        return true;
    }
}  

  Shiro ACL
  Instance-level Access Control Lists
  In this scenario you use three tokens - the first is the domain, the second is the action, and the third is the instance you are acting on.
规则:"资源标识符:操作:对象实例ID" 即对哪个资源的哪个实例可以进行什么操作。
示例:
    newsletter:edit:12,13,18        allow user to edit newsletter 12,13 and 18
    newsletter:*:13                    grant a user all actions for newsletter 13
    newsletter:view,create,edit:*    allow the user to view, create, or edit any newsletter
    newsletter:*:*                     allow the user to perform any action on any newsletter
匹配规则说明:
    如"user:view"等价于"user:view:*";而"organization"等价于"organization:*"或者"organization:*:*"。
    另外如"user:*"可以匹配"user:delete";"user:delete"可以匹配"user:delete:1";"user:*:1"可以匹配"user:view:1";"user"可以匹配"user:view"或"user:view:1"
等。
    即*可以匹配所有,不加*可以进行前缀匹配;但是如"*:view"不能匹配"system:user:view",需要使用"*:*:view",即后缀匹配必须指定前缀(多个冒号就需要多个*来匹配)。

  

  





运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-637030-1-1.html 上篇帖子: 三台主机分别部署apache,mariadb和php并实现xcache加速 下篇帖子: apache目录限制
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表