Shiro入门之授权

参阅《跟我学shiro》—— 张开涛

  授权,也叫控制访问,即在应用中你可以访问哪些资源。授权决定的是你可以做什么。在授权中需要了解几个关键对象:主体,资源,权限,角色。
  Shiro提供了三种方式的授权:
  (1)编程式:

        if(currentUser.hasRole("admin")){            
        }else{        
        }

  (2)注解式(建议将shiro注解放入controller,因为如果service层使用了spring的事物注解,那么shiro注解将无效):

@RequiresPermissions("account:create")‏
public void openAccount( Account acct ) {
}

  (3)jsp标签:

    <shiro:lacksPermission name="users:manage">
        No user management for you!
    </shiro:lacksPermission>

  对于权限,shiro还支持字符串通配符权限控制更加细粒度的权限,规则资源标识符:操作:对象实例ID,即对哪个资源的哪个实例可以进行什么样的操作,其默认支持通配符权限字符串,"*"表示任意资源|操作|实例。
  使用方式如下:
  (1)shrio.ini中的配置

[users]
# 用户名 = 密码,角色1,角色2...
user = 123456,admin  
[roles]
#角色 = 权限1,权限2
#表示admin角色拥有对所有用户的修改,所有admin的读
admin =  user:edit:*,admin:read

  (2)进行测试

    public static void main(String[] args) {

        Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        Object instance = factory.getInstance();

        SecurityUtils.setSecurityManager((org.apache.shiro.mgt.SecurityManager) instance);

        Subject currentUser = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken("user", "123456");

        if (!currentUser.isAuthenticated()) {
           currentUser.login(token);
        }

        if(currentUser.isPermitted("user:edit:1")){
            log.info("当前登录拥有: 修改id为1的用户 权限");
        }
        if(currentUser.isPermitted(new WildcardPermission("admin:read"))){
            log.info("当前登录拥有: 读取所有管理原信息 权限");
        }
        currentUser.logout();
    }

  Shiro对字符串缺失的处理支持前缀匹配,比如 "user:edit"可以匹配 "user:edit:* ","user:"可以匹配 "user:edit:","user:read:*"等等。
  通配符匹配相比于字符串相等匹配更复杂,因此需要花费长时间的比对,但是一般系统的权限不会太多,可以配合缓存提供其性能,如果这样性能还达不到要求我们可以实现位操作算法实现性能更好的权限匹配。另外实例级别的权限验证如果数据量太大也不建议使用,可能造成查询权限及匹配变慢。可以考虑比如在 sql 查询时加上权限字符串之 类的方式在查询时就完成了权限匹配。

授权流程

   Shiro的授权流程如下:
  (1)调用 isPermitterd|hasRole 时,会委托给 SecurityManager 进行鉴权,而SecurityManager 会接着委托给 Authorizer进行授权。
  (2)Authorizer才是真正的授权者,当调用 isPermitterd|hasRole 时,首先会通过 PermissionResolver 把字符串转化成相应的 Permission 实例。
  (3)在进行授权之前,会首先调用相应的 Realm 获取 Subject的所拥有的所有权限用于匹配传入的权限。
  (4)Authorizer 会判断传入的权限和用户的权限是否匹配,如果有多个 Realm,会委托给 ModularRealmAuthorizer 进行循环判断(如果有一个匹配则返回true),如果匹配如 isPermitted/hasRole会返回 true,否 则返回 false 表示授权失败。
  如果是使用 Realm 进行授权的话,应该继承 AuthorizingRealm,其流程是:
  (1)如果是 hasRole()的话,直接获取 AuthorizationInfo.getRoles()与传入的角色比较即可。
  (2)首先如果调用如 isPermitted(“user:view”),首先通过 PermissionResolver 将权限字符串转换成相应的 Permission 实例
  (3)获取AuthorizationInfo.getPermissions()获取所有的权限字符串并转化成对应的 Permission 实例。然后获取用户的角色,并且通过 RolePermissionResolver 解析角色对应的权限集合(默认没有实现,可以自己提供)。
  (4)接着调用 Permission. implies(Permission p)逐个与传入的权限比较,如果有匹配的则返回true,否则 false。
  使用方式如下:

1. 配置 shiro.ini
[users]
# 用户名 = 密码,角色1,角色2...
user = 123456,admin
[main]
authRealm = com.demo.main.MyAuthRealm
securityManager.realms = $authRealm

2. 进行测试
public class MyAuthRealm extends AuthorizingRealm {
    private static final Logger log = LoggerFactory.getLogger(MyAuthRealm.class);
    //授权方法
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String useranme = (String) principalCollection.getPrimaryPrincipal();
        log.info("去数据库查询用户:{},对应的角色信息或者权限信息", useranme);
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.addRoles(Arrays.asList("admin"));
        authorizationInfo.addStringPermission("user:read:1");
        return authorizationInfo;
    }
    //认证方法
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        Object principal = authenticationToken.getPrincipal();
        log.info("用户{}请求授权,去数据源查询对应的用户信息", principal);
        return new SimpleAuthenticationInfo(principal, authenticationToken.getCredentials(), getName());
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343