第六章:Shiro的Realms——深入浅出学Shiro细粒度权限开发框架
Realms概述
概述
Realm 是一个能够访问应用程序特定的安全数据(如用户、角色及权限)的组件。
Realm 通常和数据源是一对一的对应关系,如关系数据库,LDAP 目录,文件系统,或其他类似资源。Realm 实质上就是一个特定安全的DAO。
因为这些数据源大多通常存储身份验证数据(如密码的凭证)以及授权数据(如角色或权限),每个Realm能够执行身份验证和授权操作。
关于Realm的配置
这个在前面讲过了,这个就不去赘述了
理解Realms的认证实现
前面学到过,Shiro的认证过程最终会交由Realm执行,这时会调用Realm的getAuthenticationInfo(token)方法。
该方法通常会在org.apache.shiro.realm.AuthenticatingRealm中实现,当然,这个方法中会调用到具体realm实现的方法。
该方法主要执行以下操作:
1、检查提交的进行认证的令牌信息
2、根据令牌信息从数据源(通常为数据库)中获取用户信息
3、对用户信息进行匹配验证。
4、验证通过将返回一个封装了用户信息的AuthenticationInfo实例。
5、验证失败则抛出AuthenticationException异常信息。
这是对所有Realm getAuthenticationInfo 实现的最高级别的工作流。
验证通过后,就返回一个非空的AuthenticationInfo 实例来代表来自于该数据源的Subject 帐户信息。
Shiro默认的Realms的认证实现
所有Shiro 立即可用的Realm 的实现默认使用SimpleCredentialsMatcher。SimpleCredentialsMatcher 执行一个普通的直接相等性的检查,也就是在存储的帐户credentials 与在AuthenticationToken 所提交的之间的检查。
使用Hashing Credentials
如果要使用Hashing Credentials,那么需要在配置中告诉验证器,使用相应的匹配器,这个在前面示例过。
但是前面直接使用的Sha256Matcher,已经不推荐使用了,现在推荐使用统一的HashedCredentialsMatcher,然后配置具体的算法名称,这些名称按照Java Security Framework里面的标准名称来配置。常见的名称有:
MD5、AES 、DES 、SHA-1、SHA-256、SHA-384、SHA-512……很多
具体可以参见:http://docs.oracle.com/javase/6/docs/technotes/guides/security/StandardNames.html
新的实现配置示例:
[main]
sha256Matcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
sha256Matcher.hashAlgorithmName = SHA-256
sha256Matcher.storedCredentialsHexEncoded=false
iniRealm.credentialsMatcher = $sha256Matcher
myRealm1=cn.javass.hello.MyRealm
myRealm1.credentialsMatcher = $sha256Matcher
authenticator = org.apache.shiro.authc.pam.ModularRealmAuthenticator
authcStrategy = org.apache.shiro.authc.pam.AllSuccessfulStrategy
authenticator.authenticationStrategy = $authcStrategy
authenticator.realms=$myRealm1,iniRealm
securityManager.authenticator = $authenticator
[users]
javass =NVsbv8lnJc3Oj0onCP2jEKgObRMxWuxOXu0qdf6AMs4=,role1
[roles]
role1 = p1,p2
当然,别忘了在MyRealm中,创建SimpleAuthenticationInfo时传的密码就应该是加密后的字符串了
你还可以在密码加密的时候,加点salt,使密码更安全。这种方式目前默认的iniRealm没有支持,只能是在自己扩展的Realm里面使用
新的配置文件示例:
[main]
sha256Matcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
sha256Matcher.hashAlgorithmName = SHA-256
sha256Matcher.storedCredentialsHexEncoded=false
sha256Matcher.hashIterations = 10
myRealm1=cn.javass.hello.MyRealm
myRealm1.credentialsMatcher = $sha256Matcher
authenticator = org.apache.shiro.authc.pam.ModularRealmAuthenticator
authenticator.realms=$myRealm1
securityManager.authenticator = $authenticator
[users]
javass =kExd2f52W1M/wXidIRjOfMDj76DVo6e2md+7Rn4ubmY=,role1
[roles]
role1 = p1,p2
获得加盐后的密码字符串
String ss = new Sha256Hash("cc","javass",10).toBase64();
在自定义的realm中,返回的SimpleAuthenticationInfo需要修改一下,要加入salt的信息,当然,密码也需要是加密后的字符串,修改为:
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
username,
"kExd2f52W1M/wXidIRjOfMDj76DVo6e2md+7Rn4ubmY=" .toCharArray(),
ByteSource.Util.bytes("javass".getBytes()),
getName()
);
要保证你的Realm 实现必须返回一个SaltedAuthenticationInfo 实例而不是一个普
通的AuthenticationInfo 实例。
使用默认的JdbcRealm
这个需要在数据库中建立相应的表
然后配置相应的数据库连接,然后才能使用,这里以spring中的bean定义来说明一下,示例如下:
<bean id="myRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="dataSource" ref="dataSource" />
<property name="authenticationQuery"
value="select u.pwd from tbl_user u where u.uuid = ?" />
<property name="userRolesQuery"
value="select r.uuid from tbl_user_role ur left join tbl_role r on ur.roleUuid = r.uuid where ur.userUuid = ? " />
<property name="permissionsQuery"
value="select p.uuid from tbl_role r left join tbl_role_permission rp on r.uuid = rp.roleUuid left join tbl_permission p on rp.permissionUuid = p.uuid where r.uuid = ? " />
<property name="permissionsLookupEnabled" value="true" />
<property name="saltStyle" value="NO_SALT" />
</bean>
自定义Realm
自定义Reald非常简单,通常是继承AuthorizingRealm 抽象类,这个类实现了常用的authentication 及authorization 工作流来节省你的时间和精力。
然后覆盖doGetAuthenticationInfo,在这个方法里面实现获取用户信息
基本的示例如下:
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
//token中储存着输入的用户名和密码
UsernamePasswordToken upToken = (UsernamePasswordToken)token;
String username = upToken.getUsername();
//通常是根据用户名去数据库中查询相应信息,这里就省略了
//当然这里也可以对用户名和密码进行校验
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, password .toCharArray(),getName());
return info;
}
然后覆盖doGetAuthorizationInfo,在这个方法里面实现获取用户权限的信息
基本的示例如下:
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName = (String) getAvailablePrincipal(principals);
//通过用户名去获得用户的所有资源,并把资源存入info中
//当然这里通常会操作数据库去获取
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Set<String> s = new HashSet<String>();
s.add("p1");
s.add("p2");
info.setStringPermissions(s);
Set<String> r = new HashSet<String>();
r.add("r1");
r.add("r2");
info.setRoles(r);
return info;
}
在spring的配置文件中使用
在Spring的配置文件中,配置的内容和ini文件是一样,只不过转换成xml的风格,用bean的方式来配置
基本的示例如下:
<bean id="sha256Matcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="SHA-256"></property>
<property name="storedCredentialsHexEncoded" value="false"></property>
<property name="hashIterations" value="10"></property>
</bean>
<bean id="myRealm2" class="cn.javass.hello.MyRealm">
<property name="credentialsMatcher" ref="sha256Matcher"></property>
</bean>
而且,由于把我们的Realm配置成bean了,自然就可以使用依赖注入等功能了。
- Flash/Flex学习笔记(1):Hello World!
- 数据库常规操作
- 不伦不类的Action Script 3.0
- Asp.Net Mvc中的一些初级问题整理
- Pandas Series笔记
- Asp.Net4.0/VS2010新变化(6):内置的图表控件
- Asp.Net4.0/VS2010新变化(5):可扩展的(分布式)缓存
- Pandas对行情数据的预处理
- 上市公司*ST华泽官网打不开,域名已被挂出售卖
- Asp.Net4.0/VS2010新变化(4):SEO的改进
- Pandas DataFrame笔记
- 让控件填满整个页面
- 用多个类别来进行微调
- Asp.Net4.0/VS2010新变化(2):网站自动预热
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- parallelStream的坑,不踩不知道,一踩吓一跳
- leetcode链表之删除链表的节点
- Windows 技术篇-通过注册表查找vc运行库所在位置实战演示,通过ProductCode查看vc++运行库安装位置
- Python 库安装问题-whl is not a supported wheel on this platform.原因及解决办法
- 安装Go运行环境
- Python 语法问题-module 'pip' has no attribute 'pep425tags',告诉你如何正确查看pip支持,32位、64位查看pip支持万能方法
- 使用matplotlib绘制3D图表
- 微服务的用户认证与授权杂谈(下)
- Python 库安装问题-用pip安装pyHook3报错,原因及解决办法
- 微服务的用户认证与授权杂谈(上)
- Python 技术篇-win32、amd64结尾的whl库该选哪个,如何查看python平台支持
- Python 基础篇-pip卸载python库方法,pip命令大全
- Python 技术篇-pip安装的python库缓存位置查看方法,如何查看python库源码
- Redis持久化 - RDB和AOF
- Python 技术篇-pip只下载python库不安装方法,pip命令大全