Shiro源码分析之SecurityManager对象获取
@
上篇文章Shiro源码分析之获取SecurityManager工厂获取我们介绍了SecurityManager工厂的获取步骤,本文在此基础上来分析下SecurityManager对象产生的过程。
SecurityManager获取过程
1.SecurityManager接口介绍
SecurityManager安全管理器,是Shiro的核心,继承了三个接口,其定义的方法如下
public interface SecurityManager extends Authenticator, Authorizer, SessionManager {
// 登录
Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException;
// 注销
void logout(Subject subject);
// 获取Subject对象
Subject createSubject(SubjectContext context);
}
本文重点不是分析SecurityManager的结构,所以此处略过。
2.SecurityManager实例化时序图
3.源码分析
3.1.AbstractFactory
public T getInstance() {
T instance;
// 判断是否是单例,默认就是单例
if (isSingleton()) {
if (this.singletonInstance == null) {
// 创建实例
this.singletonInstance = createInstance();
}
instance = this.singletonInstance;
} else {
instance = createInstance();
}
if (instance == null) {
String msg = "Factory 'createInstance' implementation returned a null object.";
throw new IllegalStateException(msg);
}
return instance;
}
// 模板模式 定义抽象方法,交给子类实现
protected abstract T createInstance();
3.2 IniFactorySupport
public T createInstance() {
// 获取Ini对象 该对象在获取SecurityManager工厂的时候被实例化了
Ini ini = resolveIni();
T instance;
if (CollectionUtils.isEmpty(ini)) {
log.debug("No populated Ini available. Creating a default instance.");
instance = createDefaultInstance();
if (instance == null) {
String msg = getClass().getName() + " implementation did not return a default instance in " +
"the event of a null/empty Ini configuration. This is required to support the " +
"Factory interface. Please check your implementation.";
throw new IllegalStateException(msg);
}
} else {
log.debug("Creating instance from Ini [" + ini + "]");
// 创建实例
instance = createInstance(ini);
if (instance == null) {
String msg = getClass().getName() + " implementation did not return a constructed instance from " +
"the createInstance(Ini) method implementation.";
throw new IllegalStateException(msg);
}
}
return instance;
}
// 抽象方法 进入子类中查看
protected abstract T createInstance(Ini ini);
3.3 IniSecurityManagerFactory
protected SecurityManager createInstance(Ini ini) {
if (CollectionUtils.isEmpty(ini)) {
throw new NullPointerException("Ini argument cannot be null or empty.");
}
// 通过createSecurityManager获取实例
SecurityManager securityManager = createSecurityManager(ini);
if (securityManager == null) {
String msg = SecurityManager.class + " instance cannot be null.";
throw new ConfigurationException(msg);
}
return securityManager;
}
private SecurityManager createSecurityManager(Ini ini) {
// 获取Ini中保存的shiro.ini文件中的section的 main信息
Ini.Section mainSection = ini.getSection(MAIN_SECTION_NAME);
if (CollectionUtils.isEmpty(mainSection)) {
//try the default: 默认是 ""
mainSection = ini.getSection(Ini.DEFAULT_SECTION_NAME);
}
return createSecurityManager(ini, mainSection);
}
3.4 进入createSecurityManager方法
private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) {
// 创建默认的 SecurityManager和IniRealm 跳转到3.4.1
Map<String, ?> defaults = createDefaults(ini, mainSection);
// 绑定对象到SecurityManager对象
Map<String, ?> objects = buildInstances(mainSection, defaults);
// 从objects 中获取SecurityManager对象
SecurityManager securityManager = getSecurityManagerBean();
// 判断是否自动应用realm
boolean autoApplyRealms = isAutoApplyRealms(securityManager);
// 因为我们在shiro.ini中配置了users所以前面创建了IniRealm所以为true
if (autoApplyRealms) {
//realms and realm factory might have been created - pull them out first so we can
//initialize the securityManager:
Collection<Realm> realms = getRealms(objects);
//set them on the SecurityManager
if (!CollectionUtils.isEmpty(realms)) {
// 将IniRealm绑定到了SecurityManager中
applyRealmsToSecurityManager(realms, securityManager);
}
}
// 初始化Realm 跳至 3.5处
initRealms(securityManager);
return securityManager;
}
3.4.1 此处需要进入createDefaults查看
protected Map<String, ?> createDefaults(Ini ini, Ini.Section mainSection) {
Map<String, Object> defaults = new LinkedHashMap<String, Object>();
// 此处的代码 实例化了SecurityManager 对象
// 3.4.2进入createDefaultInstance查看
SecurityManager securityManager = createDefaultInstance();
defaults.put(SECURITY_MANAGER_NAME, securityManager);
// 判断ini中是否隐含的有realm 3.4.3查看
if (shouldImplicitlyCreateRealm(ini)) {
// 创建realm 查看createRealm方法 3.4.4查看
Realm realm = createRealm(ini);
if (realm != null) {
defaults.put(INI_REALM_NAME, realm);
}
}
return defaults;
}
3.4.2 createDefaultInstance方法
protected SecurityManager createDefaultInstance() {
// SecurityManager模式的实现是DefaultSecurityManager实例
return new DefaultSecurityManager();
}
3.4.3 shouldImplicitlyCreateRealm方法
protected boolean shouldImplicitlyCreateRealm(Ini ini) {
// 返回结果的判断条件是 ini不为空同时(ini中包含roles或者users)就为true
return !CollectionUtils.isEmpty(ini) &&
(!CollectionUtils.isEmpty(ini.getSection(IniRealm.ROLES_SECTION_NAME)) ||
!CollectionUtils.isEmpty(ini.getSection(IniRealm.USERS_SECTION_NAME)));
}
3.4.4 createRealm
protected Realm createRealm(Ini ini) {
// 我们可以看到实例化的是IniRealm对象
IniRealm realm = new IniRealm(ini);
realm.setName(INI_REALM_NAME);
return realm;
}
3.5 initRealms
private void initRealms(SecurityManager securityManager) {
Collection<Realm> realms = getRealms(securityManager);
if (!CollectionUtils.isEmpty(realms)) {
LifecycleUtils.init(realms);
}
}
3.6 LifecycleUtils
public static void init(Collection c) throws ShiroException {
if (c == null || c.isEmpty()) {
return;
}
for (Object o : c) {
init(o);
}
}
public static void init(Object o) throws ShiroException {
if (o instanceof Initializable) {
init((Initializable) o);
}
}
public static void init(Initializable initializable) throws ShiroException {
initializable.init();
}
3.7AuthorizingRealm
public final void init() {
//trigger obtaining the authorization cache if possible
getAvailableAuthorizationCache();
onInit(); // 进入IniRealm中
}
3.8 IniRealm
protected void onInit() {
// This is an in-memory realm only - no need for an additional cache when we're already
// as memory-efficient as we can be.
String resourcePath = getResourcePath();
if (CollectionUtils.isEmpty(this.users) && CollectionUtils.isEmpty(this.roles)) {
//no account data manually populated - try the resource path:
if (StringUtils.hasText(resourcePath)) {
log.debug("Resource path {} defined. Creating INI instance.", resourcePath);
Ini ini = Ini.fromResourcePath(resourcePath);
// 核心方法进入
processDefinitions(ini);
} else {
throw new IllegalStateException("No resource path was specified. Cannot load account data.");
}
} else {
if (StringUtils.hasText(resourcePath)) {
log.warn("Users or Roles are already populated. Resource path property will be ignored.");
}
}
}
processDefinitions
private void processDefinitions(Ini ini) {
if (CollectionUtils.isEmpty(ini)) {
log.warn("{} defined, but the ini instance is null or empty.", getClass().getSimpleName());
return;
}
Ini.Section rolesSection = ini.getSection(ROLES_SECTION_NAME);
if (!CollectionUtils.isEmpty(rolesSection)) {
log.debug("Discovered the [{}] section. Processing...", ROLES_SECTION_NAME);
// 处理角色信息
processRoleDefinitions(rolesSection);
}
Ini.Section usersSection = ini.getSection(USERS_SECTION_NAME);
if (!CollectionUtils.isEmpty(usersSection)) {
log.debug("Discovered the [{}] section. Processing...", USERS_SECTION_NAME);
// 处理用户信息
processUserDefinitions(usersSection);
} else {
log.info("{} defined, but there is no [{}] section defined. This realm will not be populated with any " +
"users and it is assumed that they will be populated programatically. Users must be defined " +
"for this Realm instance to be useful.", getClass().getSimpleName(), USERS_SECTION_NAME);
}
}
3.9 TextConfigurationRealm
processRoleDefinitions
protected void processRoleDefinitions(Map<String, String> roleDefs) {
if (roleDefs == null || roleDefs.isEmpty()) {
return;
}
for (String rolename : roleDefs.keySet()) {
String value = roleDefs.get(rolename);
SimpleRole role = getRole(rolename);
if (role == null) {
role = new SimpleRole(rolename);
// 添加角色
add(role);
}
Set<Permission> permissions = PermissionUtils.resolveDelimitedPermissions(value, getPermissionResolver());
// 添加权限
role.setPermissions(permissions);
}
}
processUserDefinitions
protected void processUserDefinitions(Map<String, String> userDefs) {
if (userDefs == null || userDefs.isEmpty()) {
return;
}
for (String username : userDefs.keySet()) {
String value = userDefs.get(username);
String[] passwordAndRolesArray = StringUtils.split(value);
String password = passwordAndRolesArray[0];
SimpleAccount account = getUser(username);
if (account == null) {
account = new SimpleAccount(username, password, getName());
//添加账号
add(account);
}
account.setCredentials(password);
if (passwordAndRolesArray.length > 1) {
for (int i = 1; i < passwordAndRolesArray.length; i++) {
String rolename = passwordAndRolesArray[i];
account.addRole(rolename);
SimpleRole role = getRole(rolename);
if (role != null) {
account.addObjectPermissions(role.getPermissions());
}
}
} else {
account.setRoles(null);
}
}
}
3.10 SimpleAccountRealm
protected void add(SimpleRole role) {
roles.put(role.getName(), role);
}
protected void add(SimpleAccount account) {
String username = getUsername(account);
this.users.put(username, account);
}
最后回到createSecurityManager方法中
private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) {
// 创建默认的 SecurityManager和IniRealm
Map<String, ?> defaults = createDefaults(ini, mainSection);
// 绑定对象到SecurityManager对象
Map<String, ?> objects = buildInstances(mainSection, defaults);
// 从objects 中获取SecurityManager对象
SecurityManager securityManager = getSecurityManagerBean();
// 判断是否自动应用realm
boolean autoApplyRealms = isAutoApplyRealms(securityManager);
// 因为我们在shiro.ini中配置了users所以前面创建了IniRealm所以为true
if (autoApplyRealms) {
//realms and realm factory might have been created - pull them out first so we can
//initialize the securityManager:
Collection<Realm> realms = getRealms(objects);
//set them on the SecurityManager
if (!CollectionUtils.isEmpty(realms)) {
// 将IniRealm绑定到了SecurityManager中
applyRealmsToSecurityManager(realms, securityManager);
}
}
// 初始化Realm
initRealms(securityManager);
return securityManager;
}
初始化SecurityManager完成
4.总结
- SecurityManager默认实例的是DefaultSecurityManager
- 如果我们在shiro.ini配置文件配置了[Users]的话那么会自动创建IniRealm
- 创建的IniRealm会被绑定到SecurityManager对象中,并且会将账号密码保存到SimpleAccountRealm的User集合中,认证的时候会从此对象中获取
Shiro源码分析之SecurityManager对象获取的更多相关文章
- Shiro 源码分析
http://my.oschina.net/huangyong/blog/215153 Shiro 是一个非常优秀的开源项目,源码非常值得学习与研究. 我想尝试做一次 不一样 的源码分析:源码分析不再 ...
- Spring AOP 源码分析 - 创建代理对象
1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...
- Flask框架 (四)—— 请求上下文源码分析、g对象、第三方插件(flask_session、flask_script、wtforms)、信号
Flask框架 (四)—— 请求上下文源码分析.g对象.第三方插件(flask_session.flask_script.wtforms).信号 目录 请求上下文源码分析.g对象.第三方插件(flas ...
- JVM源码分析之Java对象头实现
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 “365篇原创计划”第十一篇. 今天呢!灯塔君跟大家讲: JVM源码分析之Java对象头实现 HotSpot虚拟机中,对象在内存中的布局分为三 ...
- Shiro源码分析
1.入口类:AbstractAuthenticator 用户输入的登录信息经过其authenticate方法: public final AuthenticationInfo authenticate ...
- [旧][Android] Retrofit 源码分析之 ServiceMethod 对象
备注 原发表于2016.05.03,资料已过时,仅作备份,谨慎参考 前言 大家好,我又来学习 Retrofit 了,可能这是最后一篇关于 Retrofit 框架的文章了.我发现源码分析这回事,当时看明 ...
- HotSpot源码分析之C++对象的内存布局
HotSpot采用了OOP-Klass模型来描述Java类和对象.OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象的具体类型.为了更好理解这个模型, ...
- Spring源码分析(五)获取Document
摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 这一篇开始进行Document加载了,XmlBeanFactoryRea ...
- Springboot源码分析之代理对象内嵌调用
摘要: 关于这个话题可能最多的是@Async和@Transactional一起混用,我先解释一下什么是代理对象内嵌调用,指的是一个代理方法调用了同类的另一个代理方法.首先在这儿我要声明事务直接的嵌套调 ...
随机推荐
- HTMl、CSS、JS的区别:
HTMl.CSS.JS的区别: Html:决定网页的结构和内容----[结构] Css:控制页面的表现样式,如:美化页面----[表现] Js:控制网页的行为,如:给页面加动态的效果----[行为]
- Vue-router重修02
1.权限控制 例如:登录后登录前的页面不一样 借助路由元信息完成 一个示例: <!DOCTYPE html> <html lang="en"> <he ...
- 关于height、offsetheight、clientheight、scrollheight、innerheight、outerheight的区别
二.也是平时经常用到的offsetheight 它返回的高度是内容高+padding+边框,但是注意哦,木有加margin哦,当然一般也木有啥需要把margin加进去的,以上代码为例,结果显示上图h2 ...
- 折线图hellocharts的使用说明
以前用过一次XCL-chart,但是感觉只适合固定图表,不去滑动的那种,因为你一滑动太卡了你懂得(毕竟作者好久没更新优化了),拙言大神我开玩笑的 ,毕竟我加你的群大半年了 - - 第二研究了一下ach ...
- 2018 大湾区(深圳) .NET技术分享交流会 第一期
.NET Core 2.1 已于2018年5月30日正式发布,邀请粤港澳大湾区.NET技术专家和从业人员,一起分享与交流.NET技术的发展方向,提高粤港澳大湾区.NET技术交流氛围,挖掘.NET高级人 ...
- 合适么?现在学ASP.NET Core入门编程……
现在都快找不到ASP.NET的培训课程了. 知道我要开课做培训,有同学劝我:“憋讲那什么.NET,讲Java,现在这个火!”我说我Java不熟,“唉呀!C#转Java,分分钟的事!以飞哥你的经验,…… ...
- 【从零开始搭建自己的.NET Core Api框架】(四)实战!带你半个小时实现接口的JWT授权验证
系列目录 一. 创建项目并集成swagger 1.1 创建 1.2 完善 二. 搭建项目整体架构 三. 集成轻量级ORM框架——SqlSugar 3.1 搭建环境 3.2 实战篇:利用SqlSuga ...
- [Swift]LeetCode274.H指数 | H-Index
Given an array of citations (each citation is a non-negative integer) of a researcher, write a funct ...
- [Swift]LeetCode1009. 十进制整数的补码 | Complement of Base 10 Integer
Every non-negative integer N has a binary representation. For example, 5 can be represented as &quo ...
- Storm学习笔记 - Storm初识
Storm学习笔记 - Storm初识 1. Strom是什么? Storm是一个开源免费的分布式计算框架,可以实时处理大量的数据流. 2. Storm的特点 高性能,低延迟. 分布式:可解决数据量大 ...