什么是Shiro验证

这期内容当中小编将会给大家带来有关什么是Shiro验证,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

我们提供的服务有:成都做网站、网站制作、微信公众号开发、网站优化、网站认证、上栗ssl等。为数千家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的上栗网站制作公司

shiro验证:用户需要提供系统理解和信任的某种身份证明(密码、证书等),来证明自己可以登录该系统。
在验证阶段需要先理解几个术语:

  • Subject(主体)- 可以通俗的理解为访问应用程序的用户。只不过这个用户可以是人、第三方进程等等。

  • Principals(身份)- 主体的唯一标识属性。例如:身份证号码、手机号、邮箱等等。

  • Credentials(凭证)- 只有主体知道的安全值。例如:密码、数字证书等等。

  • Realms(领域)- 数据访问对象。用来获取Principals和Credentials。例如:用户名和密码存放在.ini文件中,可以通过IniRealm获取用户名和密码、用户名和密码存放在数据库中,可以通过JdbcRealm获取用户名和密码等等。

  • AuthenticationToken(验证令牌)- 结合Principals(身份)和Credentials(凭证)可获得的用户身份令牌。

  • Authenticator (验证者) - 验证用户验证令牌是否满足要求的科目。

  • AuthenticationStrategy(身份验证策略)- 表示以何种策略验证用户身份。

如下是从官网获取的验证架构图:
什么是Shiro验证

  • 步骤1:收集主题提交的 Principals 和 Credentials 得到 Token,应用程序代码调用Subject.login方法,传入 Token 以进行身份验证动作。

  • 步骤2:Subject实例,通常是 DelegatingSubject(或子类)通过调用 securityManager.login(token)将实际的身份验证工作委托给 SecurityManager 处理

  • 步骤3:SecurityManager 作为基本的组件,接收 Token 然后通过调用 authenticate(token)将其委托给 Authenticator。Authenticator 几乎总是实例 ModularRealmAuthenticator,它支持在身份验证期间协调一个或多个 Realm 实例。

  • 步骤4:如果为应用配置了多个 Realm ,则 ModularRealmAuthenticator 实例将使用其配置的 AuthenticationStrategy 启动多领域身份验证尝试。在调用 Realms 进行身份验证之前,期间或者之后,将调用 AuthenticationStrategy 以允许它对每个 Realm 的结果做出反应。

  • 步骤5:将咨询每个 realm 以查看是否支持已提交的 AuthenticationToken。如果是这样,将使用提交的 Token 调用 realm 的getauthenticationfo方法。getauthenticationfo方法有效地表示该特定领域的单一身份验证尝试。

接下来就开始使用ShiroAPI完成验证操作了。
环境准备:

本文使用 Maven 构建,因此需要一点 Maven 知识。首先准备环境依赖:


    
        junit
        junit
        4.9
        test
    
    
        commons-logging
        commons-logging
        1.2
    
    
        org.apache.shiro
        shiro-core
        1.3.2
    

添加 junit 和 shiro-core 依赖即可。

初识:登录 / 退出

1、首先准备一些用户身份 / 凭据(shiro.ini)

[users]
zhangsan=123
lisi=123

2、测试用例(com.luther.shiro.authenticator.AuthenticateTest)

/**
 * 底层默认使用ModularRealmAuthenticator验证模块(多realm验证) 
 * AtLeastOneSuccessfulStrategy验证策略(只要有一个域成功进行身份验证,  *  则认为成功。否则失败。会返回所有成功的用户标识)  * @author luther  * @time 2019年7月5日  上午9:58:39  */ @Test public void testHelloWorld() { // 使用Ini配置文件初始化SecurityManager Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini"); // 得到SecurityManager实例 并绑定给SecurityUtils SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); // 得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证) Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("zhangsan", "123"); // 记住用户 token.setRememberMe(Boolean.TRUE); try { // 登录 subject.login(token); System.out.println("登录成功"); } catch (AuthenticationException e) { System.err.println("登录失败,失败原因:"); e.printStackTrace(); } assertTrue("用户已验证成功", subject.isAuthenticated()); // 退出 subject.logout(); }

Realm
realm 接口结构如下,其下方法有: 什么是Shiro验证

String getName(); //返回一个唯一的Realm名字
boolean supports(AuthenticationToken token); //判断此Realm是否支持此Token
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException;  //根据Token获取认证信息

其中主要默认实现如下:
org.apache.shiro.realm.text.IniRealm:从ini文件获取用户权限等信息。
org.apache.shiro.realm.text.PropertiesRealm:从properties文件获取用户权限等信息。
org.apache.shiro.realm.jdbc.JdbcRealm:从数据库获取用户权限等信息。
以后开发一般继承 AuthorizingRealm(授权)抽象类即可;其继承了 AuthenticatingRealm(即身份验证),而且也间接继承了 CachingRealm(带有缓存实现)。

一、单 Realm 配置

1、自定义 Realm 实现(com.luther.shiro.realm.MyRealm1):

public class MyRealm1 implements Realm {

	@Override
	public String getName() {
		return this.getClass().getName();
	}

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

	@Override
	public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
		
		// 得到用户名
		String username = usernamePasswordToken.getUsername();
		// 得到密码
		String password = new String(usernamePasswordToken.getPassword());
		
		// 户名错误
		if (!"zhangsan".equals(username)) {
			throw new UnknownAccountException(); 
		}

		// 密码错误
		if (!"123".equals(password)) {
			throw new IncorrectCredentialsException(); 
		}

		System.out.println("用户" + username + "验证成功");

		// 返回
		return new SimpleAccount(username, password, getName());
	}
}

2、ini 配置文件指定自定义 Realm 实现 (shiro-realm.ini)

[main]
#声明一个realm
myRealm1=com.luther.shiro.realm.MyRealm1
#指定securityManager的realms实现,通过 $name 来引入之前的 realm 定义
securityManager.realms=$myRealm1

3、测试用例请参考 com.luther.shiro.authenticator.AuthenticateTest 的testSingleRealm 测试方法,此方法和 testHelloWorld 除了配置文件其它没有差异。

二、多 Realm 配置

1、ini 配置文件(shiro-multi-realm.ini)

[main]
#声明一个realm
myRealm1=com.luther.shiro.realm.MyRealm1
#声明一个realm
myRealm2=com.luther.shiro.realm.MyRealm2
#指定securityManager的realms实现,通过 $name 来引入之前的 realm 定义
securityManager.realms=$myRealm2,$myRealm1

#此例子中显视的指定了顺序为myRealm2,myRealm1。(可以少指定,比如只指定myRealm2,则myRealm1会被忽略)
#如果不指定securityManager.realms,则会按realm的声明(无需设置 realms 属性,其会自动发现)顺序来,此处即为myRealm1,myRealm2。

2、测试用例请参考 com.luther.shiro.authenticator.AuthenticateTest 的 testMutiRealm 测试方法。

Authenticator 及 AuthenticationStrategy

一、Authenticator 及 AuthenticationStrategy简介
Authenticator 的职责是验证用户帐号,是 Shiro API 中身份验证核心的入口点(默认实现为 ModularRealmAuthenticator ),其方法定义为:

public AuthenticationInfo authenticate(AuthenticationToken authenticationToken) throws AuthenticationException;

如果验证成功,将返回 AuthenticationInfo 验证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应的 AuthenticationException 实现。

AuthenticationStrategy 则是 Authenticator 进行验证时的验证策略 (默认实现为:AtLeastOneSuccessfulStrategy),Shiro API 自带的策略有以下三种:
FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第一个 Realm 身份验证成功的认证信息,其他的忽略。
AtLeastOneSuccessfulStrategy:只要有一个 Realm 验证成功即可,和 FirstSuccessfulStrategy 不同,返回所有 Realm 身份验证成功的认证信息。
AllSuccessfulStrategy:所有 Realm 验证成功才算成功,且返回所有 Realm 身份验证成功的认证信息,如果有一个失败就失败了。

二、Authenticator 及 AuthenticationStrategy演示
假设我们有三个 realm:
myRealm1: 用户名/密码为 zhangsan/123 时成功,且返回身份/凭据为 zhangsan/123;
myRealm2: 用户名/密码为 lisi/123 时成功,且返回身份/凭据为 lisi/123;
myRealm3: 用户名/密码为 zhangsan/123 时成功,且返回身份/凭据为 zhangsan.qq/123

1、通用化登录逻辑

private void authentition(String iniConfigPath, String username, String password) {
	// 使用Ini配置文件初始化SecurityManager
	Factory factory = new IniSecurityManagerFactory(iniConfigPath);
	// 得到SecurityManager实例 并绑定给SecurityUtils
	SecurityManager securityManager = factory.getInstance();
	SecurityUtils.setSecurityManager(securityManager);
	
	// 得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
	Subject subject = SecurityUtils.getSubject();
	UsernamePasswordToken token = new UsernamePasswordToken(username, password);
	// 记住用户
	token.setRememberMe(Boolean.TRUE);
	
	try {
		// 登录
		subject.login(token);
		System.out.println("用户zhangsan登录成功,其身份标识为" + subject.getPrincipals());
	} catch (AuthenticationException e) {
		System.err.println("登录失败,失败原因:");
		e.printStackTrace();
	}
	
	assertTrue("用户已验证成功", subject.isAuthenticated());
	
	// 退出
	subject.logout();
}

2、测试 AtLeastOneSuccessfulStrategy
2.1 ini 配置文件 (shiro-firstSuccessfulStrategy.ini)

[main]
#指定securityManager的authenticator实现,可以不指定,因为其默认实现就是ModularRealmAuthenticator
#authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
#securityManager.authenticator=$authenticator

#指定securityManager.authenticator的authenticationStrategy,可以不指定,因为其默认实现就是AtLeastOneSuccessfulStrategy
#authenticationStrategy=org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy
#securityManager.authenticator.authenticationStrategy=$authenticationStrategy

#声明一个realm
myRealm1=com.luther.shiro.realm.MyRealm1
#声明一个realm
myRealm2=com.luther.shiro.realm.MyRealm2
#声明一个realm
myRealm3=com.luther.shiro.realm.MyRealm3
#指定securityManager的realms实现,通过 $name 来引入之前的 realm 定义
securityManager.realms=$myRealm3,$myRealm2,$myRealm1

2.2 测试代码

/**
 * 演示AtLeastOneSuccessfulStrategy的效果
 * 每个realm都会进行验证,并返回全部的成功用户标识
 * @author luther
 * @time 2019年7月5日  上午11:30:24
 */
@Test
public void testAtLeastOneSuccessfulStrategy() {
	authentition("classpath:shiro-atLeastOneSuccessfulStrategy.ini", "zhangsan", "123");
}

2.3 测试结果

开始验证com.luther.shiro.realm.MyRealm3
com.luther.shiro.realm.MyRealm3 - 用户zhangsan验证成功
开始验证com.luther.shiro.realm.MyRealm2
开始验证com.luther.shiro.realm.MyRealm1
com.luther.shiro.realm.MyRealm1 - 用户zhangsan验证成功
用户zhangsan登录成功,其身份标识为zhangsan.qq,zhangsan

即 PrincipalCollection 包含了 zhangsan 和 zhangsan.qq 身份信息。

3、测试 AllSuccessfulStrategy
3.1 ini 配置文件 (shiro-allSuccessfulStrategy.ini)

[main]
#指定securityManager的authenticator实现,可以不指定,因为其默认实现就是ModularRealmAuthenticator
#authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
#securityManager.authenticator=$authenticator

#指定securityManager.authenticator的authenticationStrategy为AllSuccessfulStrategy
authenticationStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$authenticationStrategy

#声明一个realm
myRealm1=com.luther.shiro.realm.MyRealm1
#声明一个realm
myRealm2=com.luther.shiro.realm.MyRealm2
#声明一个realm
myRealm3=com.luther.shiro.realm.MyRealm3
#指定securityManager的realms实现,通过 $name 来引入之前的 realm 定义
securityManager.realms=$myRealm3,$myRealm2,$myRealm1

3.2 测试代码

/**
 * 演示AllSuccessfulStrategy的效果
 * 依次对每个realm进行验证,验证通过下一个,验证失败,直接返回失败验证原因,只有全部成功时才返回全部的用户标识
 * 每个realm都会进行验证,并返回全部的成功用户标识
 * @author luther
 * @time 2019年7月5日  上午11:30:24
 */
@Test
public void testAllSuccessfulStrategy() {
	authentition("classpath:shiro-allSuccessfulStrategy.ini", "zhangsan", "123");
}

3.3 测试结果

开始验证com.luther.shiro.realm.MyRealm3
com.luther.shiro.realm.MyRealm3 - 用户zhangsan验证成功
开始验证com.luther.shiro.realm.MyRealm2
登录失败,失败原因:
org.apache.shiro.authc.UnknownAccountException
	at com.luther.shiro.realm.MyRealm2.getAuthenticationInfo(MyRealm2.java:42)
	······

4、测试 firstSuccessfulStrategy
4.1 ini 配置文件 (shiro-firstSuccessfulStrategy.ini)

[main]
#指定securityManager的authenticator实现,可以不指定,因为其默认实现就是ModularRealmAuthenticator
#authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
#securityManager.authenticator=$authenticator

#指定securityManager.authenticator的authenticationStrategy为FirstSuccessfulStrategy
authenticationStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$authenticationStrategy

#声明一个realm
myRealm1=com.luther.shiro.realm.MyRealm1
#声明一个realm
myRealm2=com.luther.shiro.realm.MyRealm2
#声明一个realm
myRealm3=com.luther.shiro.realm.MyRealm3
#指定securityManager的realms实现,通过 $name 来引入之前的 realm 定义
securityManager.realms=$myRealm3,$myRealm2,$myRealm1

4.2 测试代码

/**
 * 演示FirstSuccessfulStrategy的效果
 * 会对每个realm进行验证,全部验证完后会返回验证成功的第一个用户标识(此处需注意,不是依次验证立马返回,而是全部验证再返回)
 * @author luther
 * @time 2019年7月5日  上午11:30:24
 */
@Test
public void testFirstSuccessfulStrategy() {
	authentition("classpath:shiro-firstSuccessfulStrategy.ini", "zhangsan", "123");
}

4.3 测试结果

开始验证com.luther.shiro.realm.MyRealm3
com.luther.shiro.realm.MyRealm3 - 用户zhangsan验证成功
开始验证com.luther.shiro.realm.MyRealm2
开始验证com.luther.shiro.realm.MyRealm1
com.luther.shiro.realm.MyRealm1 - 用户zhangsan验证成功
用户zhangsan登录成功,其身份标识为zhangsan.qq

以上已经演示了API自带的验证策略,以下稍微演示下自定义的验证策略。
自定义 AuthenticationStrategy 实现之前,首先简单看其 API:

//在所有Realm验证之前调用
AuthenticationInfo beforeAllAttempts(
Collection realms, AuthenticationToken token) 
throws AuthenticationException;
//在每个Realm之前调用
AuthenticationInfo beforeAttempt(
Realm realm, AuthenticationToken token, AuthenticationInfo aggregate) 
throws AuthenticationException;
//在每个Realm之后调用
AuthenticationInfo afterAttempt(
Realm realm, AuthenticationToken token, 
AuthenticationInfo singleRealmInfo, AuthenticationInfo aggregateInfo, Throwable t)
throws AuthenticationException;
//在所有Realm之后调用
AuthenticationInfo afterAllAttempts(
AuthenticationToken token, AuthenticationInfo aggregate) 
throws AuthenticationException;

5、自定义验证策略(com.luther.shiro.authenticationStrategy.LastSuccessfulStrategy)

/**
 * 验证所有realm,并返回最后一个验证通过的身份标识
 * @author luther
 * @time 2019年7月5日  下午4:12:31
 */
public class LastSuccessfulStrategy extends AbstractAuthenticationStrategy {
	
	// 第一种方案修改afterAttempt方法
	@Override
	public AuthenticationInfo afterAttempt(Realm realm, AuthenticationToken token, AuthenticationInfo singleRealmInfo,
			AuthenticationInfo aggregateInfo, Throwable t) throws AuthenticationException {
		return singleRealmInfo;
	}

//	// 第二种方案修改merge方法
//	@Override
//	protected AuthenticationInfo merge(AuthenticationInfo info, AuthenticationInfo aggregate) {
//		if (info != null) {
//			aggregate = info;
//		}
//		
//		return aggregate;
//	}
	
}

5.1 ini 配置文件 (shiro-lastSuccessfulStrategy.ini)

[main]
#指定securityManager的authenticator实现,可以不指定,因为其默认实现就是ModularRealmAuthenticator
#authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
#securityManager.authenticator=$authenticator

#指定securityManager.authenticator的authenticationStrategy为自定义的LastSuccessfulStrategy
authenticationStrategy=com.luther.shiro.authenticationStrategy.LastSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$authenticationStrategy

#声明一个realm
myRealm1=com.luther.shiro.realm.MyRealm1
#声明一个realm
myRealm2=com.luther.shiro.realm.MyRealm2
#声明一个realm
myRealm3=com.luther.shiro.realm.MyRealm3
#指定securityManager的realms实现,通过 $name 来引入之前的 realm 定义
securityManager.realms=$myRealm3,$myRealm2,$myRealm1

5.2 测试代码

/**
 * 演示自定义的LastSuccessfulStrategy的效果
 * 会对每个realm进行验证,全部验证完后会返回验证成功的最后一个用户标识	
 * @author luther
 * @time 2019年7月5日  上午11:30:24
 */
@Test
public void testLastSuccessfulStrategy() {
	authentition("classpath:shiro-lastSuccessfulStrategy.ini", "zhangsan", "123");
}

5.3 测试结果

开始验证com.luther.shiro.realm.MyRealm3
com.luther.shiro.realm.MyRealm3 - 用户zhangsan验证成功
开始验证com.luther.shiro.realm.MyRealm2
开始验证com.luther.shiro.realm.MyRealm1
com.luther.shiro.realm.MyRealm1 - 用户zhangsan验证成功
用户zhangsan登录成功,其身份标识为zhangsan

上述就是小编为大家分享的什么是Shiro验证了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注创新互联行业资讯频道。


分享标题:什么是Shiro验证
文章URL:http://scyanting.com/article/gcjdci.html