• 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.总结

    1. SecurityManager默认实例的是DefaultSecurityManager
    2. 如果我们在shiro.ini配置文件配置了[Users]的话那么会自动创建IniRealm
    3. 创建的IniRealm会被绑定到SecurityManager对象中,并且会将账号密码保存到SimpleAccountRealm的User集合中,认证的时候会从此对象中获取
  • 相关阅读:
    java 各种运行组件下载地址
    Exchange 2013故障XOWAError: System.NullReferenceException
    已整理sshpass 脚本应用案例
    已整理head 与 tail 的特殊用法(除尾行和去掉首行)
    如何删除exchange 2013 邮件队列
    分布式事务锁
    GRPC
    identityserver4 Showing login: User is not authenticated
    Selenium 中的 JUnit 注解
    Groovy语境下的Map
  • 原文地址:https://www.cnblogs.com/dengpengbo/p/10500827.html
Copyright © 2020-2023  润新知