shiro关于认证的学习

一、shiro认证入门程序工程

 

shiro分为认证和授权,这里我们先学习shiro的认证。

 

1、shiro认证流程

 

 

2、shiro认证入门工程的搭建

 

(1)首先创建一个java工程

 

 

在eclipse中显示的工程结构

 

 

(2)添加shiro的jar包

 

最核心的jar包就是:shiro-core.jar(下边其他的是需要依赖的jar包)

在工程中创建一个lib文件夹(Folder),把jar包拷贝进去,然后build path。

 

在eclipse中显示的工程结构

 

 

这里我也贴一下,用maven时候,pom文件中的坐标

 

<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-core</artifactId>
	<version>1.2.3</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-web</artifactId>
	<version>1.2.3</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-spring</artifactId>
	<version>1.2.3</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-ehcache</artifactId>
	<version>1.2.3</version>
</dependency>
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-quartz</artifactId>
	<version>1.2.3</version>
</dependency>

也可以通过引入shiro-all包括shiro所有的包:
<dependency>
	<groupId>org.apache.shiro</groupId>
	<artifactId>shiro-all</artifactId>
	<version>1.2.3</version>
</dependency>

 

 

 

 

 

(3)创建一个log4j的日志文件

 

创建一个config文件夹(Source Folder),把log4j的日志文件贴进去。

 

这里可以简短的贴一下log4j日志文件最基本的内容

 

log4j.rootLogger=debug,stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n


到时候创建一个log4j.properties文件,把上边的贴入进去就可以了。

 

 

在eclipse中显示的工程结构

 

 

这样我们这个最入门的工程就搭建好了。

 

3、开始写shiro测试Demo

 

首先我们创建一个包com.shiro.authentication,创建一个测试类AnthenticationTest.java。

 

我们在测试这个环境中,并没有连接数据库,而是创建一个ini文件,在测试运行的时候加载ini文件里边配置的内容,就相当于从数据库中比对了。(ini文件相对于properties文件,就是可以分组,而properties文件只是简单的key,value形式)

 

ini文件配置的内容

(ini配置文件放在config文件夹中)

 

 

接下来是测试类的内容

 

package com.shiro.authentication;

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.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;

/**
 * 
 * <p>Title: AnthenticationTest</p>
 * <p>Description: 认证测试</p>
 * <p>Company: www.zonsim.com</p> 
 * @author	Liuyl
 * @date	2016年10月5日上午12:14:55
 * @version 1.0
 */
public class AnthenticationTest {
	
	// 用户登陆和退出
	@Test
	public void testLoginAndLogout(){
		
		/**
		 * (1)构建securityManager环境
		 */
		// 创建securityManager工厂,通过ini配置文件创建securityManager工厂(ini是window中的一种配置文件)
		Factory<SecurityManager> factory = new IniSecurityManagerFactory(
				"classpath:shiro-first.ini");
		//在ini里进行的配置,SecurityManager创建的时候就把ini里边的信息加载进来了,就相当于查询数据库了
		//在说明一些SecurityManager类要导入org.apache.shiro.mgt.SecurityManager;包

		
		// 创建SecurityManager
		SecurityManager securityManager = factory.getInstance();
		//通过创建SecurityManager工厂和创建SecurityManager对象,完成了第一步构建securityManager环境

		
		/**
		 * 这个算是中间衔接的过程
		 */	
		// 将securityManager设置当前的运行环境中(这里是单例里的,但是不用我们管理,SecurityUtils完成这件事)
		SecurityUtils.setSecurityManager(securityManager);
		
		/**
		 * 现在是一个测试环境,需要模拟一个subject,这里需要我们构造出来。
		 * 正常情况下,这个subject不需要我们来管,到时候就是我的一个http请求就是subject
		 */
		// 从SecurityUtils里边创建一个subject
		Subject subject = SecurityUtils.getSubject();


		/**
		 * (2)执行认证提交
		 */	
		// 在认证提交前准备token(令牌)
		// 这里的账号和密码 将来是由用户输入进去
		UsernamePasswordToken token = new UsernamePasswordToken("zhangsan",
				"111111");
		
		//我们在认证的时候可以抛出一个异常
		try {
			//认证提交
			subject.login(token);
		} catch (AuthenticationException e) {//AuthenticationException:shiro自己的认证异常
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		/**
		 * (3)得到一个验证的结果
		 */
		// 是否认证通过
		boolean isAuthenticated = subject.isAuthenticated();

		System.out.println("是否认证通过:" + isAuthenticated);

		// 退出操作
		subject.logout();//一退出,身份信息就没有了
		
		// 是否认证通过
		isAuthenticated = subject.isAuthenticated();

		System.out.println("是否认证通过:" + isAuthenticated);//退出了就因该是false了
				
		/**
		 * 整体的流程就是token中的用户名密码要和ini配置文件里边的用户名密码进行比对,
		 * 成功了就是true,没有就是false
		 */
		
	}

}

 

4、测试结果说明

 

(1)上边测试的就过是true,false。

在执行程序的时候,会拿着UsernamePasswordToken产生的token,去对面ini配置文件里边定义的帐号密码。有就返回true。

当退出之后,身份信息就没有了,在进行身份认证,就是返回false了。

 

(2)如果用户名不对

会报帐号不存在异常:org.apache.shiro.authc.UnknownAccountException

返回结果则是false,false

 

(3)如果密码不正确

会报凭证错误异常:org.apache.shiro.authc.IncorrectCredentialsException

返回结果则是false,false

 

5、总结shrio认证执行流程

 

 

@1.通过ini配置文件创建securityManager。


@2.调用subject.login方法主体提交认证,提交的token。


@3.securityManager进行认证,securityManager通过Authenticator接口,最终由(调用)ModularRealmAuthenticator进行认证。


@4.ModularRealmAuthenticator调用IniRealm(给realm传入的token)去ini配置文件中查询用户信息。


@5.IniRealm根据输入的token(UsernamePasswordToken)从shiro-first.ini(自己定义的ini文件)查询用户信息,根据账号查询用户信息(账号和密码)

如果查询到用户信息,就给ModularRealmAuthenticator返回用户信息(账号和密码),

如果查询不到,就给ModularRealmAuthenticator返回null(说明账号不存在)。


@6.ModularRealmAuthenticator接收IniRealm返回Authentication认证信息,
如果返回的认证信息是null,ModularRealmAuthenticator抛出异常(org.apache.shiro.authc.UnknownAccountException)。

如果返回的认证信息不是null(说明inirealm找到了用户),ModularRealmAuthenticator对IniRealm返回用户密码(在ini文件中存在)和token中的密码进行对比,如果不一致抛出异常(org.apache.shiro.authc.IncorrectCredentialsException)

 

 

二、自定义reaml认证

 

 

将来实际开发需要realm从数据库中查询用户信息。

 

1、在项目中创建一个realm包com.shiro.realm

 

 

2、开始创建自定义realm类

 

这个自定义realm类一般继承AuthorizingRealm这个类。

 

 

下面就是自定义realm类

 

 

package com.shiro.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;

/**
 * 
 * <p>Title: CustomRealm</p>
 * <p>Description: 自定义realm</p>
 * <p>Company: www.zonsim.com</p> 
 * @author	Liuyl
 * @date	2016年10月5日下午3:47:58
 * @version 1.0
 */
public class CustomRealm extends AuthorizingRealm{
	
	// 设置realm的名称(这里边就读取ini配置文件中的数据)
	@Override
	public void setName(String name) {
		super.setName("customRealm");
	}

	/**
	 * 需要实现AuthorizingRealm这个接口的两个方法
	 */
	
	//用户认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		
		//因为我们现在还不连接数据库,我们在这里模拟一下
		//第一步从token中取出身份信息( token是用户输入的)(这里边userCode取到的值是前边测试类中UsernamePasswordToken设置的值)
		String userCode = (String) token.getPrincipal();
		
		
		// 第二步:根据用户输入的userCode从数据库查询
		// ....
		
		
		//下边这步是模拟没有找到用户时候的情况
		// 如果查询不到返回null
		//数据库中用户账号是zhangsansan
		if(!userCode.equals("zhangsansan")){//
			return null;
		}
		
		
		// 模拟从数据库查询到密码
		String password = "111111";
		
		
		// 如果查询到返回认证信息AuthenticationInfo
		//参数1.身份信息 2.凭证3.realm的名称
		SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
				userCode, password, this.getName());
		
		return simpleAuthenticationInfo;
		
	}
	
	//用户授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		// TODO Auto-generated method stub
		return null;
	}

}

 

 

 

3、配置自定义realm

 

 

自定义reaml定义好之后,要对realm进行配置,如果不配置realm,securityManager就不知道调用哪个realm。
所以需要在shiro-realm.ini(也可以配置到shiro-first.ini)配置realm注入到securityManager中。

 

ini配置文件的内容为:

 

 

4、写测试类进行测试

 

就是上边测试类,改变一下加载的ini配置文件名称,不加载shiro-first.ini,改为加载shiro-realm.ini

 

 

这样完成了自定义realm的认证方式。

以后的开发中都会用自定义realm的方式来写。

最后测试的结果,同上边的入门工程测试结果一样。

 

 

三、自定义realm支持散列算法的认证

 

1、首先了解一下加密的散列算法

 

通常需要对密码进行散列,常用的有md5、sha,(md5散列后就不能逆向了)。


对md5密码,如果知道散列后的值可以通过穷举算法,得到md5密码对应的明文。
建议对md5进行散列时加salt(盐),进行加密相当于对原始密码+盐进行散列。


正常使用时散列方法:
在程序中对原始密码+盐进行散列,将散列值存储到数据库中,并且还要将盐也要存储在数据库中。
如果进行密码对比时,使用相同方法,将原始密码+盐进行散列,进行比对。

 

2、先来一个加密的测试程序,继续了解一下

 

 

package com.shiro.authentication;

import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.junit.Test;

/**
 * 
 * <p>Title: MD5Test</p>
 * <p>Description: </p>
 * <p>Company: www.zonsim.com</p> 
 * @author	Liuyl
 * @date	2016年10月5日下午4:36:30
 * @version 1.0
 */
public class MD5Test {


	@Test
	public void MD5_Test(){
		//原始 密码 
		String source = "111111";
		//盐
		String salt = "qwerty";
		//散列次数
		int hashIterations = 2;
		//上边散列1次:f3694f162729b7d0254c6e40260bf15c
		//上边散列2次:36f2dfa24d0a9fa97276abbe13e596fc
		
		
		//构造方法中:
		//第一个参数:明文,原始密码 
		//第二个参数:盐,通过使用随机数
		//第三个参数:散列的次数,比如散列两次,相当 于md5(md5(''))
		Md5Hash md5Hash = new Md5Hash(source, salt, hashIterations);
		
		//得到md5散列后的密码
		String password_md5 =  md5Hash.toString();
		System.out.println(password_md5);
		
		
		//第一个参数:散列算法 (这个和上边的作用是一样的)
		SimpleHash simpleHash = new SimpleHash("md5", source, salt, hashIterations);
		System.out.println(simpleHash.toString());
	}
}

 

 

 

3、接下来,写最重要的支持散列算法的自定义realm

 

 

 

package com.shiro.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;

/**
 * 
 * <p>Title: CustomRealm</p>
 * <p>Description: 自定义realm</p>
 * <p>Company: www.zonsim.com</p> 
 * @author	Liuyl
 * @date	2016年10月5日下午3:47:58
 * @version 1.0
 */
public class CustomRealmMD5 extends AuthorizingRealm{
	
	// 设置realm的名称
	@Override
	public void setName(String name) {
		super.setName("customRealmMD5");
	}

	/**
	 * 需要实现AuthorizingRealm这个接口的两个方法
	 */
	
	//用户认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		
		//因为我们现在还不连接数据库,我们在这里模拟一下
		//第一步从token中取出身份信息( token是用户输入的)(这里边userCode取到的值是前边测试类中UsernamePasswordToken设置的值)
		String userCode = (String) token.getPrincipal();
		
		
		// 第二步:根据用户输入的userCode从数据库查询
		// ....
		
		
		/*//下边这步是模拟没有找到用户时候的情况
		// 如果查询不到返回null
		//数据库中用户账号是zhangsansan
		if(!userCode.equals("zhangsansan")){//
			return null;
		}*/
		
		
		// 模拟从数据库查询到密码,进行散列后的值(原来的明文密码是111111)
		String password = "f3694f162729b7d0254c6e40260bf15c";
		// 从数据库获取salt
		String salt = "qwerty";
		
		
		// 如果查询到返回认证信息AuthenticationInfo
		//参数1.身份信息 2.凭证3.盐4.realm的名称
		SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
				userCode, password, ByteSource.Util.bytes(salt), this.getName());
		
		return simpleAuthenticationInfo;
		
	}
	
	//用户授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
		// TODO Auto-generated method stub
		return null;
	}

}

 

 

 

4、同上,需要配置自定义realm

 

 

这里需要把凭证匹配器和自定义的realm都定义到realm中。

 

ini配置文件的内容为:

 


5、写测试类进行认证测试

 

就是上边测试类,改变一下加载的ini配置文件名称,不加载shiro-realm.ini,改为加载shiro-realm-md5.ini

 

 

这种方式基本上都用这种。

最后测试的结果,同上边的入门工程测试结果一样。

 

 

这样关于shiro认证方面的使用方法和知识点都介绍完成了。

 

 

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值