关于身份认证中的Authenticator及AuthenticationStrategy
在流程图3中,有Authenticator和AuthenticationStrategy2个接口。
Authenticator的职责是验证用户帐号,是Shiro API中身份验证核心的入口点:
它只有一个方法:
public AuthenticationInfo authenticate(AuthenticationToken authenticationToken)throws AuthenticationException;
如果验证成功,将返回 AuthenticationInfo 验证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应的 AuthenticationException 实现。
选中AuthenticationInfo,按住Ctrl+t,可以看到它的继承体系。
SecurityManager接口继承了Authenticator,另外还有一个ModularRealmAuthenticator实现,其委托给多个Realm进行验证,验证规则通过AuthenticationStrategy接口指定,默认提供的实现:
FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;
AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。
ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。
一个例子:
假设我们有三个realm:
myRealm1: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang/123;
myRealm2: 用户名/密码为wang/123时成功,且返回身份/凭据为wang/123;
myRealm3: 用户名/密码为zhang/123时成功,且返回身份/凭据为zhang@163.com/123,和myRealm1不同的是返回时的身份变了;
三个reaml文件如下:
package com.lgy.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.Realm;public class MyRealm1 implements Realm {public String getName() {return "myrealm1";}public boolean supports(AuthenticationToken token) {return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token}public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String username = (String)token.getPrincipal(); //得到用户名String password = new String((char[])token.getCredentials()); //得到密码if(!"zhang".equals(username)) {throw new UnknownAccountException(); //如果用户名错误}if(!"123".equals(password)) {throw new IncorrectCredentialsException(); //如果密码错误}//如果身份认证验证成功,返回一个AuthenticationInfo实现;return new SimpleAuthenticationInfo(username, password, getName());}
}package com.lgy.shiro;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.Realm;public class MyRealm2 implements Realm {public String getName() {return "myrealm2";}public boolean supports(AuthenticationToken token) {return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token}public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String username = (String)token.getPrincipal(); //得到用户名String password = new String((char[])token.getCredentials()); //得到密码if(!"wang".equals(username)) {throw new UnknownAccountException(); //如果用户名错误}if(!"123".equals(password)) {throw new IncorrectCredentialsException(); //如果密码错误}//如果身份认证验证成功,返回一个AuthenticationInfo实现;return new SimpleAuthenticationInfo(username, password, getName());}
}package com.lgy.shiro;import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.realm.Realm;public class MyRealm3 implements Realm {public String getName() {return "myrealm3";}public boolean supports(AuthenticationToken token) {return token instanceof UsernamePasswordToken; //仅支持UsernamePasswordToken类型的Token}public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String username = (String)token.getPrincipal(); //得到用户名String password = new String((char[])token.getCredentials()); //得到密码if(!"zhang".equals(username)) {throw new UnknownAccountException(); //如果用户名错误}if(!"123".equals(password)) {throw new IncorrectCredentialsException(); //如果密码错误}//如果身份认证验证成功,返回一个AuthenticationInfo实现;return new SimpleAuthenticationInfo(username + "163@qq.com", password, getName());}
}
封装的login代码如下:
private void login(String configFile) {//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManagerFactory<org.apache.shiro.mgt.SecurityManager> factory =new IniSecurityManagerFactory(configFile);//2、得到SecurityManager实例 并绑定给SecurityUtilsorg.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");subject.login(token);}@Afterpublic void tearDown() throws Exception {ThreadContext.unbindSubject();//退出时请解除绑定Subject到线程 否则对下次测试造成影响}
上面说的:
默认策越(ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略。)DEMO
ini文件:
[main]#声明一个realmmyRealm1=com.lgy.shiro.MyRealm1
myRealm2=com.lgy.shiro.MyRealm2
myRealm3=com.lgy.shiro.MyRealm3
#指定securityManager的realms实现securityManager.realms=$myRealm1,$myRealm2,$myRealm3
测试如下:
@Testpublic void testStrategyWithdefault() {login("classpath:shiro-auth-default.ini");
// login("classpath:shiro-realm.ini");Subject subject = SecurityUtils.getSubject();/*boolean b = subject.isAuthenticated();System.out.println(b);*///得到一个身份集合,其包含了Realm验证成功的身份信息PrincipalCollection principalCollection = subject.getPrincipals();System.out.println(principalCollection.asList().size()); //返回所有的身份凭证信息//Assert.assertEquals(2, principalCollection.asList().size());}
验证信息是zhang/123, myRealm1和myRealm2是能通过的,打印返回的size为2,正如前面所说的:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息;
FirstSuccessfulStrategy策越,demo如下:
ini文件:
[main]#指定securityManager的authenticator实现
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
securityManager.authenticator=$authenticator
#指定securityManager.authenticator的authenticationStrategy
firstSuccessfulStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$firstSuccessfulStrategy #声明一个realmmyRealm1=com.lgy.shiro.MyRealm1
myRealm2=com.lgy.shiro.MyRealm2
myRealm3=com.lgy.shiro.MyRealm3
#指定securityManager的realms实现securityManager.realms=$myRealm1,$myRealm2,$myRealm3
测试代码:
@Testpublic void testStrategyWithdefirst() { login("classpath:shiro-auth-first.ini");Subject subject = SecurityUtils.getSubject();System.out.println(subject.isAuthenticated());PrincipalCollection principalCollection = subject.getPrincipals();System.out.println(principalCollection.asList().size());}
验证信息是zhang/123, myRealm1和myRealm2是能通过的,打印返回的size为1,正如前面所说的只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略;
AllSuccessfulStrategy测试,demo如下:
ini文件:
[main]#指定securityManager的authenticator实现
authenticator=org.apache.shiro.authc.pam.ModularRealmAuthenticator
securityManager.authenticator=$authenticator
#指定securityManager.authenticator的authenticationStrategy
allSuccessfulStrategy=org.apache.shiro.authc.pam.AllSuccessfulStrategy
securityManager.authenticator.authenticationStrategy=$allSuccessfulStrategy #声明一个realmmyRealm1=com.lgy.shiro.MyRealm1
myRealm2=com.lgy.shiro.MyRealm2
myRealm3=com.lgy.shiro.MyRealm3
#指定securityManager的realms实现securityManager.realms=$myRealm1,$myRealm2,$myRealm3
测试文件:
@Testpublic void testStrategyWithdeAll() { login("classpath:shiro-auth-all.ini");Subject subject = SecurityUtils.getSubject();System.out.println(subject.isAuthenticated());PrincipalCollection principalCollection = subject.getPrincipals();System.out.println(principalCollection.asList().size());}
验证信息是zhang/123, myRealm1和myRealm3是能通过的,但是myRealm2不是通过,所以会抛出异常,测试部通过。 将myRealm2中的wang改为zhang,所以验证能通过,打印为2,为什么?因为返回凭证中myRealm1和myRealm2一样被当做同一个凭证。
关于身份认证中的Authenticator及AuthenticationStrategy相关推荐
- 无线局域网(WLAN)系统中身份认证中ikey1000的具体应用
本文来自:www.kttec.net 你是否幻想过躺在酒店舒适的沙发收发来自远方的客户订单呢?是否想过外出时也可以享受到和家中一样的安全无线接入服务?现在这些都能通过NTT东日本电信电报株式会社为您提 ...
- 数据库与身份认证(数据库的基本概念,安装并配置 MySQL,MySQL 的基本使用,在项目中操作 MySQL,前后端的身份认证)
theme: channing-cyan 数据库与身份认证 1. 数据库的基本概念 1.1 什么是数据库 数据库(database)是用来组织.存储和管理数据的仓库. 当今世界是一个充满着数据的互联网 ...
- Shiro系列-Authenticator和AuthenticationStrategy是什么
导语 之前的博客中分享了关于身份认证以及Realm的内容其中提到了一个比较关键的类,AuthenticationInfo也就是认证信息的类.怎么样去获取到这个身份 认证的信息类呢? 文章目录 Au ...
- Shiro(三) 身份认证源码分析与 MD5 盐值加密
文章目录 1. 身份认证 2. 身份验证的基本流程 3. 身份验证实现 3.1 在 `login.jsp` 添加登录表单 3.2 添加表单提交的 Controller 3.3 完善 Realm 的身份 ...
- [信息安全] 4.一次性密码 amp;amp;amp;amp; 身份认证三要素
在信息安全领域,一般把Cryptography称为密码,而把Password称为口令.日常用户的认知中,以及我们开发人员沟通过程中,绝大多数被称作密码的东西其实都是Password(口令),而不是真正 ...
- 浅析Windows域环境身份认证与攻击思路
文章目录 前言 Kerberos协议 第1步-AS认证获取TGT 第2步-TGS认证获取ST 第3步-服务端服务认证 NTLM 认证 本地认证模式 网络认证模式 内网横向渗透 哈希凭证窃取 内网远程连 ...
- [转载]细说ASP.NET Windows身份认证
细说ASP.NET Windows身份认证 阅读目录 开始 认识ASP.NET Windows身份认证 访问 Active Directory 在ASP.NET中访问Active Directory ...
- 细说ASP.NET Forms身份认证
细说ASP.NET Forms身份认证 阅读目录 开始 ASP.NET身份认证基础 ASP.NET身份认证过程 如何实现登录与注销 保护受限制的页面 登录页不能正常显示的问题 认识Forms身份认证 ...
- 详解Spring Security进阶身份认证之UserDetailsService(附源码)
在上一篇Spring Security身份认证博文中,我们采用了配置文件的方式从数据库中读取用户进行登录.虽然该方式的灵活性相较于静态账号密码的方式灵活了许多,但是将数据库的结构暴露在明显的位置上,绝 ...
最新文章
- 自组织映射网络(SOM)+Kohonen自组织网络
- dagger android 学习(二):AndroidInjector的使用
- 告别2019,写给2020:干好技术,要把握好时光里的每一步
- SmartGWT入门,提供出色的GWT界面
- python读取json格式的超参数
- 小米台灯底座接口很松_小米黑科技,AirPods和小米10 Pro伴侣,ZMI无线充蓝牙音箱体验...
- linux用于开发qt java_Linux下Qt程序的打包发布
- 线程安全的list之synchronizedList和CopyOnWriteArrayList
- 基于SURF算法的图像拼接方法
- radius mysql md5_radius协议采用什么传输 radius协议中md5加密函数的参数怎么处理
- 最简单的进制转换(三张图片搞定)
- 数据仓库实施步骤与关键成功因素
- 思科模拟器CiscoPacketTracer下载
- mysql 转大写_mysql将字符串转换为大写的方法
- Win10 - 使用‘Alt+Tab’不能切换窗口及更改切换风格
- Linux命令详解之 cp
- java volatile理解
- cocos2d-x3.2中用shader使图片背景透明
- 【云原生 | Kubernetes 系列】--Envoy熔断
- draftsight的热补丁