Shiro的环境搭建和认证操作

发表时间:2018-03-19 10:47:41 浏览量( 48 ) 留言数( 0 )

学习目标:

1、了解Shiro的环境搭建

2、掌握Shrio的基本使用

3、掌握Shiro的认证过程


学习过程:

    导入Shiro的相关包,这里把几个常用的都导入了。与web整合的shiro-web、与spring整合的shiro-spring、任务调度quartz整合的shiro-quartz等,缓存支持shiro-ehcache,下边是shiro的maven配置,当然如果你不写导入那么多。直接使用shiro-all就包含了上面的5个配置了。代码如下:

<!-- 		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<version>${shiro.version}</version>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-web</artifactId>
			<version>${shiro.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>${shiro.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-ehcache</artifactId>
			<version>${shiro.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-quartz</artifactId>
			<version>${shiro.version}</version>
		</dependency> -->

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-all</artifactId>
			<version>${shiro.version}</version>
		</dependency>

一、实现最简单得认证

1、模拟用户名和密码;

在资源目录下建立用户名和密码,以后可以通过数据库,这里先不那么复杂

shiro.ini,内容如下:

[users]
liubao=123
zhangsan=123

测试代码:

public class ShrioTest1 {
	// 用户登陆、用户退出
	@Test
	public void testLogin() {

		// 构建SecurityManager工厂,IniSecurityManagerFactory可以从ini文件中初始化SecurityManager环境
		Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
		// 通过工厂创建SecurityManager
		SecurityManager securityManager = factory.getInstance();

		// 将securityManager设置到运行环境中
		SecurityUtils.setSecurityManager(securityManager);

		// 创建一个Subject实例,该实例认证要使用上边创建的securityManager进行
		Subject subject = SecurityUtils.getSubject();
		// 创建token令牌,记录用户认证的身份和凭证即账号和密码
		UsernamePasswordToken token = new UsernamePasswordToken("liubao", "123");
		try {
			// 用户登陆
			subject.login(token);
		} catch (AuthenticationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		// 用户认证状态
		Boolean isAuthenticated = subject.isAuthenticated();
		System.out.println("用户认证状态:" + isAuthenticated);

		// 用户退出
		subject.logout();
		isAuthenticated = subject.isAuthenticated();

		System.out.println("用户认证状态:" + isAuthenticated);

	}
}

代码逻辑:

1、创建token令牌,token中有用户提交的认证信息即账号和密码

2、执行subject.login(token),最终由securityManager通过Authenticator进行认证

3、Authenticator的实现ModularRealmAuthenticator调用realm从ini配置文件取用户真实的账号和密码,这里使用的是IniRealm(shiro自带)

4、IniRealm先根据token中的账号去ini中找该账号,如果找不到则给ModularRealmAuthenticator返回null,如果找到则匹配密码,匹配密码成功则认证通过。


二、使用自定义Realm

    一般用户名密码等信息我们都是保存在数据库中,需要从数据库中查询获得,这里就需要使用Realm了。前面我们介绍过Realm,Realm即领域,相当于datasource数据源,securityManager进行安全认证需要通过Realm获取用户权限数据。最基础的是Realm接口,CachingRealm负责缓存处理,AuthenticationRealm负责认证,AuthorizingRealm负责授权,通常自定义的realm继承AuthorizingRealm。

自定义Realm代码如下:

public class CustomRealmFirst extends AuthorizingRealm {

	@Override
	public String getName() {
		return "CustomRealmFirst";
	}

	// 支持UsernamePasswordToken
	@Override
	public boolean supports(AuthenticationToken token) {
		return token instanceof UsernamePasswordToken;
	}

	// 认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

		// 从token中 获取用户身份信息
		String username = (String) token.getPrincipal();
		// 
		// 以后这里需要根据username从数据库中查询,如果查询不到则返回null
		if (!username.equals("liubao")) {// 这里模拟查询不到
			return null;
		}
		// 获取从数据库查询出来的用户密码
		String password = "123";

		// 返回认证信息由父类AuthenticatingRealm进行认证
		SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(username, password, getName());

		return simpleAuthenticationInfo;
	}

	// 授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		return null;
	}
}

2、配置shiro-realm.ini

[main]
#自定义 realm
customRealm=com.shiro.CustomRealmFirst
#将realm设置到securityManager
securityManager.realms=$customRealm

测试代码

   测试代码上面一样,改一下shiro-realm.ini就可以了。

   Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");


三、散列算法

    散列算法一般用于生成一段文本的摘要信息,散列算法不可逆,将内容可以生成摘要,无法将摘要转成原始内容。散列算法常用于对密码进行散列,常用的散列算法有MD5、SHA。

    一般散列算法需要提供一个salt(盐)与原始内容生成摘要信息,这样做的目的是为了安全性,比如:111111的md5值是:96e79218965eb72c92a549dd5a330112,拿着“96e79218965eb72c92a549dd5a330112”去md5破解网站很容易进行破解,如果要是对111111和salt(盐,一个随机数)进行散列,这样虽然密码都是111111加不同的盐会生成不同的散列值。

1、md5加密例子

public class Md5Salt {

	@Test
	public void testSalt() {
		// md5加密,不加盐
		String password_md5 = new Md5Hash("123").toString();
		System.out.println("md5加密,不加盐=" + password_md5);

		// md5加密,加盐,一次散列
		String password_md5_sale_1 = new Md5Hash("123", "haha", 1).toString();
		System.out.println("password_md5_sale_haha=" + password_md5_sale_1);
		
		// 两次散列相当于md5(md5())

		// 使用SimpleHash
		String simpleHash = new SimpleHash("MD5", "123", "haha", 1).toString();
		System.out.println(simpleHash);
	}

}


2、自定义realm,并使用盐和散列

   实际应用是将盐和散列后的值存在数据库中,自动realm从数据库取出盐和加密后的值由shiro完成密码校验。

public class CustomRealmSalt extends AuthorizingRealm {

	@Override
	public String getName() {
		return "CustomRealmSalt";
	}

	// 支持UsernamePasswordToken
	@Override
	public boolean supports(AuthenticationToken token) {
		return token instanceof UsernamePasswordToken;
	}

	// 认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

		// 从token中 获取用户身份信息
		String username = (String) token.getPrincipal();
		// 
		// 以后这里需要根据username从数据库中查询,如果查询不到则返回null
		if (!username.equals("liubao")) {// 这里模拟查询不到
			return null;
		}

		//数据库保存的密码,用户输入的密码还是123
		//按照固定规则加密码结果 ,此密码 要在数据库存储,原始密码 是123,盐是haha
		String password = "01ddae4032e17a1c338baac9c4322b30";
		//盐,随机数,此随机数也在数据库存储
		String salt = "haha";
				
		//返回认证信息
		SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
						username, password, ByteSource.Util.bytes(salt),getName());
		
		return simpleAuthenticationInfo;
	}

	// 授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		// TODO Auto-generated method stub
		return null;
	}

}


3、realm配置

配置shiro-cryptography.ini

[main]
#定义凭证匹配器
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#散列算法
credentialsMatcher.hashAlgorithmName=md5
#散列次数
credentialsMatcher.hashIterations=1

#将凭证匹配器设置到realm
customRealm=com.shiro.CustomRealmSalt
customRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$customRealm


4、测试代码

测试代码同上个章节,注意修改ini路径。

Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realmsalt.ini");