一、前言
前面我们通过url拦截器实现了权限验证,功能齐全,开发难度也不大。但是为了更好的进行开发权限,开发我们选择shrio,终于扯上正题了是不是?当你学习shrio你会发现,都是一样的。嘎嘎
shiro使用广泛,shiro可以运行在web应用,非web应用,集群分布式应用中越来越多的用户开始使用shiro。简单好用用的人就多了哦。
二、shrio基础
首先一样来个图:
2.1看图说话
定要细心品味,结合url拦截器权限。。。
subject:用户或者程序,可以是任何语言编写。(这个跟uel拦截器一样)
securityManager:安全管理器,对全部的subject进行安全管理,它是shiro的核心,负责对所有的subject进行安全管理。通过SecurityManager可以完成subject的认证、授权等,实质上SecurityManager是通过Authenticator进行认证,通过Authorizer进行授权,通过SessionManager进行会话管理等。它自身只是一个接口。
Authentic:认证器,Authenticator是一个接口,shiro提供ModularRealmAuthenticator实现类,通过ModularRealmAuthenticator基本上可以满足大多数需求,也可以自 定义认证器。(相当于ur权限l的登录拦截器哦)
Authorizer:Authorizer即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限(相当于url权限系统的权限拦截器)。
sessionManager:即会话管理,shiro框架定义了一套会话管理,它不依赖web容器的session,所以shiro可以使用在非web应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录。(相当于ur权限系统里面自带的httpsession,而它可以独立)
sessionDao:SessionDAO即会话dao,是对session会话操作的一套接口,比如要将session存储到数据库,可以通过jdbc将会话存储到数据库。
realms:领域相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据,比如:如果用户身份数据在数据库那么realm就需要从数据库获取用户身份信息。(相当于ur权限系统里面自带的mysql,而它还支持验证)
注意:不要把realm理解成只是从数据源取数据,在realm中还有认证授权校验的相关的代码。
cacheManager: CacheManager即缓存管理,将用户权限数据存储在缓存,这样可以提高性能。
Cryptography:Cryptography即密码管理,shiro提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能。MD5即是散列(相当于ur权限系统里面MD5)
二、shrio的jar包
<!--======================================shrio=================================================-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-quartz</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-all</artifactId>
<version>1.2.4</version>
</dependency>
三、shrio的ini认证程序实例
项目分析
3.1加入jar包
加入上面的jar包core包即可以再加入日志文件与包
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.0</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
3.3 编写ini文件
shrio-frist.ini
#用户信息配置
[users]
zhangsan=111
ycy=222
3.4 编写测试类
我们根据项目流程一步步来编写我们的测试程序,
即是:读取ini或者xml文件----创建securityManager----加入运行环境----生成一个sbject---登录(加入taken)---退出
- 1、通过ini配置文件创建securityManager
- 2、调用subject.login方法主体提交认证,提交的token
- 3、securityManager进行认证,securityManager最终由ModularRealmAuthenticator进行认证。
- 4、ModularRealmAuthenticator调用IniRealm(给realm传入token) 去ini配置文件中查询用户信息
- 5、IniRealm根据输入的token(UsernamePasswordToken)从 shiro-first.ini查询用户信息,根据账号查询用户信息(账号和密码)
- 如果查询到用户信息,就给ModularRealmAuthenticator返回用户信息(账号和密码)
- 如果查询不到,就给ModularRealmAuthenticator返回null
- 6、ModularRealmAuthenticator接收IniRealm返回Authentication认证信息 如果返回的认证信息是null,ModularRealmAuthenticator抛出异常(org.apach e.shiro.authc.UnknownAccountException)
-
如果返回的认证信息不是null(说明inirealm找到了用户),对IniRealm返回用户密码 (在ini文件中存在)和 token中的密码 进行对比,如果不一致抛出异常(org.apache.shiro.authc.IncorrectCredentialsException)
- 注意:1、是realm调用token信息,进行验证。
- 2、securityManager是调用ModularRealmAuthenticator进行认证返回AuthenticationInfo认证信息
authenticationTest.java
package co.ycy.authenticator;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.util.Factory;
import org.junit.Test;
/**
* Created by Administrator on 2015/10/15 0015.
* 认证测试
*/
public class authenticationTest {
//用户登录和退出
@Test
public void testLoginAndLoginOut(){
//创建一个securityManager 通过ini文件创建
Factory<SecurityManager> securityManagerFactory=new IniSecurityManagerFactory("classpath:shrio-frist.ini");
// XMLSecurityManager
//创建SecurityManager
SecurityManager securityManager= securityManagerFactory.getInstance();
//将SecurityManager创建到生成环境中
SecurityUtils.setSecurityManager(securityManager);
//从SecurityUtils 构建一个subject
org.apache.shiro.subject.Subject subject=SecurityUtils.getSubject();
//认证提交认证token
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("ycy","222");
//执行认证提交认证
try {
subject.login(usernamePasswordToken);
}catch(AuthenticationException ex){
ex.printStackTrace();
}
System.out.println("是否通过认证:" + subject.isAuthenticated());
//退出
subject.logout();
System.out.println("是否通过认证:" + subject.isAuthenticated());
}
}
3.5 测试结果
四、shrio的ini认证-realms自定义
我们知道realm就是数据源,即是我们经常说的各种数据库,但是我们前面例子用的是ini文件,我们现在来模拟一下用数据。(模拟)4.1编写自定义realm
自定义realm,继承我们的AuthorizingRealm。因为AuthorizingRealm就是我们realm的一个实现类
<span style="font-size:12px;">package com.ycy.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
/**
* Created by Administrator on 2015/10/15 0015.
* 自定义数据源
*/
public class CustomRealm extends AuthorizingRealm{
//用户认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//authenticationToken为用户输入信息
String userCode=(String)authenticationToken.getPrincipal();
//模拟数据库操作查询用户
if(!userCode.equals("ycy")){
return null;
}
//查询密码为111
String password="222";
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(userCode,password,"customRealm");
return info;
}
//用户授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}</span>
4.1ini文件
这个ini文件是制定我们的realms,而不再是指定数据
shrio-realm.ini
#用户信息配置
[main]
#自定义realm
cutomRealm= com.ycy.realm.CustomRealm
#自定义realm注入到securityManager中(标签语言)
securityManager.realms=$cutomRealm
4.3 测试
测试程序一样没有变,只是现在执行认证的时候进行的是我们自己定义的realm的认证
//用户登录和退出(自定义realm)
@Test
public void testCustomRealm(){
//创建一个securityManager 通过ini文件创建
Factory<SecurityManager> securityManagerFactory=new IniSecurityManagerFactory("classpath:shrio-realm.ini");
// XMLSecurityManager
//创建SecurityManager
SecurityManager securityManager= securityManagerFactory.getInstance();
//将SecurityManager创建到生成环境中
SecurityUtils.setSecurityManager(securityManager);
//从SecurityUtils 构建一个subject
org.apache.shiro.subject.Subject subject=SecurityUtils.getSubject();
//认证提交认证token
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("ycy","222");
//执行认证提交认证
try {
subject.login(usernamePasswordToken);
}catch(AuthenticationException ex){
ex.printStackTrace();
}
System.out.println("是否通过认证:" + subject.isAuthenticated());
//退出
subject.logout();
System.out.println("是否通过认证:" + subject.isAuthenticated());
}
测试结果一样,就不用贴图了。
四、shrio的ini认证-realms自定义(加密)
只需要在realm里面写入加密就ok
4.1了解shrio的MD5加密
package com.ycy.test;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
/**
* Created by Administrator on 2015/10/15 0015.
*/
public class MD5Test {
public static void main(String[] args) {
//原始密码
String source="111";
//盐
String salt="ycy";
//散列次数
int hashInterration=1;//MD5(****)一次
Md5Hash md5Hash=new Md5Hash(source,salt,hashInterration);
String password_md5=md5Hash.toString();
System.out.println("111加盐MD5加密后为:"+password_md5);
//散列加密2
SimpleHash simpleHash=new SimpleHash("md5",source,salt,hashInterration);
System.out.println("111加盐MD5加密后为:"+simpleHash.toString());
//96c26c8872da9d2534bf7c31f499425d
}
}
4.2 修改ini文件
[main]
#定义凭证匹配
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#定义散列算法
credentialsMatcher.hashAlgorithmName=md5
#散列次数
credentialsMatcher.hashIterations=1
#自定义realm
customRealm= com.ycy.realm.CustomRealm2
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm
4.3修改自定义realm
package com.ycy.realm;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
/**
* Created by Administrator on 2015/10/15 0015.
* 自定义数据源
*/
public class CustomRealm2 extends AuthorizingRealm{
//用户认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//authenticationToken为用户输入信息
String userCode=(String)authenticationToken.getPrincipal();
//模拟数据库操作查询用户
if(!userCode.equals("ycy")){
return null;
}
//查询密码为111
//数据库111 MD5加盐ycy 加密后为96c26c8872da9d2534bf7c31f499425d
String password="96c26c8872da9d2534bf7c31f499425d";
String salt="ycy";
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(userCode,password, ByteSource.Util.bytes(salt),"customRealm");
return info;
}
//用户授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
4.4测试
//用户登录和退出(自定义realm)加密
@Test
public void testCustomRealmMd5(){
//创建一个securityManager 通过ini文件创建
Factory<SecurityManager> securityManagerFactory=new IniSecurityManagerFactory("classpath:shrio-realm-md5.ini");
// XMLSecurityManager
//创建SecurityManager
SecurityManager securityManager= securityManagerFactory.getInstance();
//将SecurityManager创建到生成环境中
SecurityUtils.setSecurityManager(securityManager);
//从SecurityUtils 构建一个subject
org.apache.shiro.subject.Subject subject=SecurityUtils.getSubject();
//认证提交认证token
UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("ycy","111");
//执行认证提交认证
try {
subject.login(usernamePasswordToken);
}catch(AuthenticationException ex){
ex.printStackTrace();
}
System.out.println("是否通过认证:" + subject.isAuthenticated());
//退出
subject.logout();
System.out.println("是否通过认证:" + subject.isAuthenticated());