千家信息网

什么是Shiro验证

发表于:2025-02-12 作者:千家信息网编辑
千家信息网最后更新 2025年02月12日,这期内容当中小编将会给大家带来有关什么是Shiro验证,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。shiro验证:用户需要提供系统理解和信任的某种身份证明(密码、
千家信息网最后更新 2025年02月12日什么是Shiro验证

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

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

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

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

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

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

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

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

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

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

  • 步骤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=123lisi=123

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

/** * 底层默认使用ModularRealmAuthenticator验证模块(多realm验证) 
* AtLeastOneSuccessfulStrategy验证策略(只要有一个域成功进行身份验证, * 则认为成功。否则失败。会返回所有成功的用户标识) * @author luther * @time 2019年7月5日 上午9:58:39 */@Testpublic 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 接口结构如下,其下方法有:

String getName(); //返回一个唯一的Realm名字boolean supports(AuthenticationToken token); //判断此Realm是否支持此TokenAuthenticationInfo 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]#声明一个realmmyRealm1=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]#声明一个realmmyRealm1=com.luther.shiro.realm.MyRealm1#声明一个realmmyRealm2=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#声明一个realmmyRealm1=com.luther.shiro.realm.MyRealm1#声明一个realmmyRealm2=com.luther.shiro.realm.MyRealm2#声明一个realmmyRealm3=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 */@Testpublic void testAtLeastOneSuccessfulStrategy() {        authentition("classpath:shiro-atLeastOneSuccessfulStrategy.ini", "zhangsan", "123");}

2.3 测试结果

开始验证com.luther.shiro.realm.MyRealm3com.luther.shiro.realm.MyRealm3 - 用户zhangsan验证成功开始验证com.luther.shiro.realm.MyRealm2开始验证com.luther.shiro.realm.MyRealm1com.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为AllSuccessfulStrategyauthenticationStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategysecurityManager.authenticator.authenticationStrategy=$authenticationStrategy#声明一个realmmyRealm1=com.luther.shiro.realm.MyRealm1#声明一个realmmyRealm2=com.luther.shiro.realm.MyRealm2#声明一个realmmyRealm3=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 */@Testpublic void testAllSuccessfulStrategy() {        authentition("classpath:shiro-allSuccessfulStrategy.ini", "zhangsan", "123");}

3.3 测试结果

开始验证com.luther.shiro.realm.MyRealm3com.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为FirstSuccessfulStrategyauthenticationStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategysecurityManager.authenticator.authenticationStrategy=$authenticationStrategy#声明一个realmmyRealm1=com.luther.shiro.realm.MyRealm1#声明一个realmmyRealm2=com.luther.shiro.realm.MyRealm2#声明一个realmmyRealm3=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 */@Testpublic void testFirstSuccessfulStrategy() {        authentition("classpath:shiro-firstSuccessfulStrategy.ini", "zhangsan", "123");}

4.3 测试结果

开始验证com.luther.shiro.realm.MyRealm3com.luther.shiro.realm.MyRealm3 - 用户zhangsan验证成功开始验证com.luther.shiro.realm.MyRealm2开始验证com.luther.shiro.realm.MyRealm1com.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为自定义的LastSuccessfulStrategyauthenticationStrategy=com.luther.shiro.authenticationStrategy.LastSuccessfulStrategysecurityManager.authenticator.authenticationStrategy=$authenticationStrategy#声明一个realmmyRealm1=com.luther.shiro.realm.MyRealm1#声明一个realmmyRealm2=com.luther.shiro.realm.MyRealm2#声明一个realmmyRealm3=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 */@Testpublic void testLastSuccessfulStrategy() {        authentition("classpath:shiro-lastSuccessfulStrategy.ini", "zhangsan", "123");}

5.3 测试结果

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

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

0