前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Shiro源码分析之SecurityManager对象获取

Shiro源码分析之SecurityManager对象获取

作者头像
用户4919348
发布2019-04-02 11:08:16
5640
发布2019-04-02 11:08:16
举报
文章被收录于专栏:波波烤鸭波波烤鸭

  上篇文章Shiro源码分析之获取SecurityManager工厂获取我们介绍了SecurityManager工厂的获取步骤,本文在此基础上来分析下SecurityManager对象产生的过程。

SecurityManager获取过程

1.SecurityManager接口介绍

  SecurityManager安全管理器,是Shiro的核心,继承了三个接口,其定义的方法如下

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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方法

代码语言:javascript
复制
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查看

代码语言:javascript
复制
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方法

代码语言:javascript
复制
protected SecurityManager createDefaultInstance() {
	// SecurityManager模式的实现是DefaultSecurityManager实例
    return new DefaultSecurityManager();
}

3.4.3 shouldImplicitlyCreateRealm方法

代码语言:javascript
复制
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

代码语言:javascript
复制
 protected Realm createRealm(Ini ini) {
 	// 我们可以看到实例化的是IniRealm对象
     IniRealm realm = new IniRealm(ini);
     realm.setName(INI_REALM_NAME);
     return realm;
 }

3.5 initRealms

代码语言:javascript
复制
private void initRealms(SecurityManager securityManager) {
    Collection<Realm> realms = getRealms(securityManager);
    if (!CollectionUtils.isEmpty(realms)) {
        LifecycleUtils.init(realms);
    }
}

3.6 LifecycleUtils

代码语言:javascript
复制
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

代码语言:javascript
复制
public final void init() {
    //trigger obtaining the authorization cache if possible
    getAvailableAuthorizationCache();
    onInit(); // 进入IniRealm中
}

3.8 IniRealm

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
protected void add(SimpleRole role) {
    roles.put(role.getName(), role);
}
代码语言:javascript
复制
 protected void add(SimpleAccount account) {
     String username = getUsername(account);
     this.users.put(username, account);
 }
在这里插入图片描述
在这里插入图片描述

最后回到createSecurityManager方法中

代码语言:javascript
复制
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.总结

  1. SecurityManager默认实例的是DefaultSecurityManager
  2. 如果我们在shiro.ini配置文件配置了[Users]的话那么会自动创建IniRealm
  3. 创建的IniRealm会被绑定到SecurityManager对象中,并且会将账号密码保存到SimpleAccountRealm的User集合中,认证的时候会从此对象中获取
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019年03月09日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • SecurityManager获取过程
    • 1.SecurityManager接口介绍
      • 2.SecurityManager实例化时序图
        • 3.源码分析
          • 4.总结
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档