Shiro快速入门

一.Shiro简介

  Shiro框架是和spring security框架作用差不多的一个安全认证授权框架,但它更加的轻便和简单,越来越多的企业在使用它进行角色权限,安全认证等方面功能的管理.

二.主要架构阅览

Shrio架构图

  Subject 主体,既可以代表用户,也可以代表程序(网络爬虫等),它需要访问系统,系统则需要对其进行认证和授权.

        SecurityManager 安全管理,用户请求Url,对应于一个Subject对象,由SecurityManager统一对Subject进行认证和授权.(父)

        Authenricator 认证部分,主要对Subject进行认证,Subject的信息在shrio中是通过AuthenticationToken对象来储存,由Authenrication进行验证管理.(子)

  Authorizer 授权部分,Subject认证后,由它来对其授予对应角色权限.(子)

  SessionManager Shiro的session管理方式,Shiro提供了一个专门管理session的方式,通常的web程序中的session是HttpSession的对象,是由web容器来管理的.

  SessionDao session的接口,Shiro通过它来管理session数据,个性化的session数据储存需要使用sessionDao.

  CacheManager  缓存管理工具,主要对session数据和授权数据进行缓存,减小数据库的访问压力.可以通过和ehcache的整合对缓存数据进行管理.

  Pluggable Realms 可扩展领域,相当于数据源,我们通过上面内容可以大致了解到Shiro的工作原理,但Shiro是怎样得知Subject的信息和数据库的信息是否匹配呢?Shiro这里就提供了一个realms的概念,它的作用就是得到数据库中的信息.这个realm是可以多个并且可以自定义,只需继承AuthorizingRealm这个接口就可以了.

  注意:对Subject进行认证和授权都需要调用realm,所以realm不仅仅相当于数据源,更加包含了认证和授权的一种逻辑.

  Cryptography  密码演算法,一个密码管理工具,提供了一套加密/解密的组件.比如长用的散列,加/解密等功能,日常练习所使用的md5算法其实是一种散列算法,只能加密,不能解密.

可见Shrio的核心部分还是认证和授权部分,其他都是围绕这俩部分进行的,只需理解了这两部分就可以进行开发了.

三.Shiro认证实例(入门案例)

Shiro处理一个Subject流程图


Shrio流程图1

Shiro处理认证流程图,相当于上图的扩充和细化


Shrio流程图1

可见,Shiro处理流程是一级一级的调用,主要是调用Authentication来进行验证,最后还是需要使用realm来进行身份验证(realm后面会提).

有了基本的执行流程图,大概就能懂了Shiro的运行原理,接下来实践一下,首先新建一个普通的java工程,导入shiro-core.jar包


Shrio jar包

这个作为入门程序导入这一个核心包就行了,建立测试代码,我这里用的是junit,也可以直接main()走起.代码如下:

//模拟用户登录登出

@Test

public void demo1(){

//创建SecurityManager工厂,生成SecurityManager环境(通过shrio的ini文件),      Factory<SecurityManager>  factory  =  new          IniSecurityManagerFactory("classpath:shrio.ini");

//创建SecurityManager

SecurityManager manager= factory.getInstance();

//将当前环境设为SecurityManager

SecurityUtils.setSecurityManager(manager);

//模拟Subject

Subject subject = SecurityUtils.getSubject();

//提交认证是说携带的信息储存在 token 中

UsernamePasswordToken token = new UsernamePasswordToken("Floder", "Floder");

try {

 //模拟获取登陆

 subject.login(token);

} catch (AuthenticationException e) {

e.printStackTrace();

}

//判断是否认证通过

boolean isOk = subject.isAuthenticated();

System.out.println("用户是否登录:"+isOk);

//模拟用户退出登陆

subject.logout();

isOk = subject.isAuthenticated();

System.out.println("用户是否登录:"+isOk);

}

这里有几点要说明的,

1.这里需要配置Shiro的配置文件,我看了一下源码,是通过InputStream来扫描配置文件,所以文件名任意.需要表明路径即可,classpath即为项目的src目录下,Shiro.ini的配置如下

#自定义数据源 格式 用户名=密码

[users]

Floder=Floder

2.构建工厂时Factory的泛型SecurityManager需要是用的是SecurityManager的接口,因为java.lang.SecurityManager也存在...

Shiro授权流程图

Shiro授权流程图

和认证流程图差不多,不过这个调用的是Authrizer模块

在进行实际操作前,需要理解Shiro的两个重要概念

1.基于角色管理:根据用户的相应角色授予相应的资源权限,但这样做有点不好的地方就是每新增一个角色都要对角色进行相应的资源权限管理(超级QQ,QQ会员),在实际开发中太过麻烦,不经常使用.

2.基于资源管理:对资源的访问需要一定的权限,这样的话每新增一个角色只需在权限对应的资源进行角色新增即可.特别方便.

测试代码:

//模拟用户认证授权

@Test

public void testAuthorizer(){

//创建SecurityManager工厂,生成SecurityManager环境(通过shrio的ini文件),//通过ini配置文件创建

securityManagerFactory factory = new IniSecurityManagerFactory("classpath:shrio-permission.ini");

//创建SecurityManager

SecurityManager manager= factory.getInstance();

//将当前环境设为SecurityManager

SecurityUtils.setSecurityManager(manager);

//模拟Subject

Subject subject = SecurityUtils.getSubject();

//提交认证是说携带的信息储存在 Token 中

UsernamePasswordToken token = new UsernamePasswordToken("Floder", "Floder");

//模拟获取登陆

try {

subject.login(token);

} catch (AuthenticationException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

//基于角色判断

//判断已认证用户是否拥有role1角色

boolean isHasRole = subject.hasRole("role2");

System.out.println("判断已认证用户是否拥有role2角色 "+isHasRole);

//也可以判断已认证用户是否有多个角色

boolean isHasAllRoles = subject.hasAllRoles(Arrays.asList("role1","role2"));

System.out.println("判断已认证用户是否有多个角色"+isHasAllRoles);

//基于资源判断

//判断已认证用户的资源是否拥有对应单个的操作

boolean isPermitted = subject.isPermitted("user:create");

System.out.println("判断已认证用户的资源是否拥有对应的单个操作 "+isPermitted);

//判断已认证用户的资源是否拥有对应的多个操作

boolean isPermittedAll = subject.isPermittedAll("user:create","user:update");

System.out.println("判断已认证用户的资源是否拥有对应的多个操作 "+isPermittedAll);

}

这里需要新建一个Shrio-permission.ini配置文件,具体信息如下:

#用户对应的角色

#用户Floder拥有角色role1和role2

[users]

Floder = Floder,role1,role2

floder=floder,role2

#角色对应的资源权限

[roles]

#权限标识符符号规则 资源:操作:实例 user:create:01 表示对用户资源实例01进行create操作

#user:create 表示对资源进行create操作,相当于user:create:*

#user:*:01 表示对用户资源实例01进行所有操作

role1=user:create,user:update

role2 = user:create

  和Shrio认证一样,只不过这里的user新增的角色栏,另外还对[roles]进行了相应的权限设置,看代码即可,注释都写的清清楚楚

  通过这两个认证和授权实例,大概能理解了ini文件起的作用,一般是相当于数据源,在Shiro中就是Realm,注意,Realm不仅仅起数据源的作用,更加包含了认证和授权的一种逻辑.重要的事说两遍

四.自定义Realm实现


在上一节中我们并没有自定义realm,那它是怎样调用认证和授权的一种逻辑呢?原来,Shiro默认提供了一个IniRealm实现,但我们知道,可以自定义Realm实现来实现我们的需求,只需实现AuthorizingRealm接口就行了(常用是这个),Realm有多种接口:

Realm结构图


Realm继承关系图


具体继承那个接口看需求,我们测试的时候就使用AuthorizingRealm

自定义UserRealm:

//设置realm名,需要继承setName()方法

@Override

public void setName(String name) {

super.setName("userName");

}

//认证方法

@Override

protected AuthenticationInfo doGetAuthenticationInfo(

AuthenticationToken token) throws AuthenticationException {

//得到token的用户信息

String userId = (String) token.getPrincipal();

//模拟数据库返回数据,如果不存在就返回null

//.......

//模拟数据库返回数据,存在就返回一个credentials

String password = "Floder";

SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userId, password, this.getName());

return info;

}

//授权方法(依赖于上面的认证信息)

@Override

protected AuthorizationInfo doGetAuthorizationInfo(

PrincipalCollection principals) {

String userId = (String) principals.getPrimaryPrincipal();

//模拟从数据库得来的角色信息,

List<String> listPermission = new ArrayList<String>();

//模拟用户创建权限

listPermission.add("user:create");

//模拟用户添加权限

listPermission.add("user:update");

//这里的info使用的是SimpleAuthorizationInfo

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

//SimpleAuthorizationInfo携带的是数据库返回的信息,数据实现的是collection接口的玩意info.addStringPermissions(listPermission);

return info;

   这里如果需要模拟null就很简单了,写个if()判断即可,这里的info信息我们实现的是SimpleAuthenticationInfo接口和SimpleAuthenticationInfo授权接口,

      我们知道realm是与数据库打交道的,由于有了自定义realm,我们就不用在ini文件中写[users]了,所以修改Shiro.ini文件的信息:

[main]

#声明我们自定义的realm

userRealm=com.floder.junit.realm.UserRealm

#将realm放入SecurityManager中

SecurityManager.realms=$userRealm

好了,准备工作都完成了,接下来开始测试,认证登陆模拟和上一节模拟登陆代码相同,授权测试代码需要修改部分代码:

try {

//模拟获取登陆

subject.login(token);

} catch (AuthenticationException e) {

e.printStackTrace();

}

//基于资源判断

//判断已认证用户的资源是否拥有对应的操作

boolean isPermitted = subject.isPermitted("user:create");

System.out.println("判断已认证用户的资源是否拥有对应的操作 "+isPermitted);

//使用check方法进行授权,如果不通过则抛出异常

subject.checkPermission("item:add");//这是需要添加的,基于角色就不需要测试了

注释这么清楚,就不解释了.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容