设为首页 收藏本站
查看: 511|回复: 0

[经验分享] Apache Shiro学习笔记(七)IniWebEnvironment

[复制链接]

尚未签到

发表于 2018-11-19 12:15:47 | 显示全部楼层 |阅读模式
鲁春利的工作笔记,好记性不如烂笔头
  

  IniWebEnvironment
  在通过JavaSE方式解析权限信息时,是通过IniSecurityManagerFactory来实现的,其中也指定了默认的ini文件路径(IniFactorySupport):
public static final String DEFAULT_INI_RESOURCE_PATH = "classpath:shiro.ini";  

  IniWebEnvironment提供了在JavaWeb下加载解析权限信息的方式。

package org.apache.shiro.web.env;
/**
* 通过ini配置文件或资源路径实现WebEnvironment配置功能
*/
public class IniWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable {
    public static final String DEFAULT_WEB_INI_RESOURCE_PATH = "/WEB-INF/shiro.ini";
    private Ini ini;
    public void init() {
        // ini未被设置过,getIni获取到null
        Ini ini = getIni();
        // 在EnvironmentLoaderListener分析时,通过ResourceBasedWebEnvironment.setConfigLocations设置了config文件路径
        String[] configLocations = getConfigLocations();
        if (log.isWarnEnabled() && !CollectionUtils.isEmpty(ini) && configLocations != null && configLocations.length > 0) {
            // 告警信息:ini已经被配置了,但config也被配置了,暂时IniWebEnvironment不支持同时配置,不过将来可能会支持
        }
        // 通过configLocations路径对应的ini文件创建Ini实例
        if (CollectionUtils.isEmpty(ini)) {
            log.debug("Checking any specified config locations.");
            ini = getSpecifiedIni(configLocations);
        }
        // 如果通过configLocations路径配置的ini文件创建Ini实例失败
        if (CollectionUtils.isEmpty(ini)) {
            log.debug("No INI instance or config locations specified.  Trying default config locations.");
            ini = getDefaultIni();    // 获取默认的Ini
        }
        if (CollectionUtils.isEmpty(ini)) {
            // 实例化ini对象失败,可能是configLocations路径配置错误或配置的文件无效
        }
        // 到了这里再进行set,设置ini实例
        setIni(ini);
        // 真正的权限解析及过滤的代码实现
        configure();
    }
    protected void configure() {
        // this.objects为父类DefaultEnvironment的变量protected final Map objects;
        this.objects.clear();
        WebSecurityManager securityManager = createWebSecurityManager();
        // 父类DefaultWebEnvironment的setWebSecurityManager方法,会继续调用其父类DefaultEnvironment
        setWebSecurityManager(securityManager);
        // ShiroFilter中setSecurityManager(env.getWebSecurityManager());也清晰了
        // 实际得到的是PathMatchingFilterChainResolver
        FilterChainResolver resolver = createFilterChainResolver();
        if (resolver != null) {    // 调用DefaultWebEnvironment.setObject方法进行设置,在ShiroFilter中就可以获取到了
            setFilterChainResolver(resolver);
        }
    }
    // 创建SecurityManager(DefaultWebSecurityManager)
    protected WebSecurityManager createWebSecurityManager() {
        // public class WebIniSecurityManagerFactory extends IniSecurityManagerFactory
        // 和在JavaSE环境下使用IniSecurityManagerFactory的方式一样了
        WebIniSecurityManagerFactory factory;
        Ini ini = getIni();
        if (CollectionUtils.isEmpty(ini)) {
            factory = new WebIniSecurityManagerFactory();
        } else {
            factory = new WebIniSecurityManagerFactory(ini);
        }
        WebSecurityManager wsm = (WebSecurityManager)factory.getInstance();
        //SHIRO-306 - get beans after they've been created (the call was before the factory.getInstance() call,
        //which always returned null.
        Map beans = factory.getBeans();
        if (!CollectionUtils.isEmpty(beans)) {
            this.objects.putAll(beans);
        }
        return wsm;
    }
    // 根据configLocations配置的ini文件生成ini实例(预处理configLocations)
    protected Ini getSpecifiedIni(String[] configLocations) throws ConfigurationException {
        Ini ini = null;
        if (configLocations != null && configLocations.length > 0) {
            if (configLocations.length > 1) {
                // 告警信息:配置了多个shiro.ini文件,但是只有第一个会被使用,现在还不支持配置多个,将来可能支持
            }
            //required = true, as it is user specified : 创建失败抛出ConfigurationException异常
            ini = createIni(configLocations[0], true);
        }
        return ini;
    }
    // 根据configLocations配置的ini文件生成ini实例(真正生成ini的操作)
    protected Ini createIni(String configLocation, boolean required) throws ConfigurationException {
        Ini ini = null;
        if (configLocation != null) {
            // convertPathToIni中以流的形式加载configLocation文件(ResourceUtils.getInputStreamForPath(path))
            // configLocation在web.xml的配置支持classpath:、url:、file:等多种形式。
            // ini = new Ini(); ini.load(is);    // 在ini的load方法中会解析ini文件(如[main]、[urls]、[filters])并进行封装
            ini = convertPathToIni(configLocation, required);
        }
        if (required && CollectionUtils.isEmpty(ini)) {
            // 抛出异常,ini文件没有找到无法创建ini实例
        }
        return ini;
    }
    // 如果通过指定的configLocations无法创建Ini实例,则使用默认加载路径尝试生成Ini实例
    protected Ini getDefaultIni() {
        Ini ini = null;
        // 获取系统默认ini文件路径
        String[] configLocations = getDefaultConfigLocations();
        if (configLocations != null) {
            for (String location : configLocations) {
                // required = false,系统默认ini文件创建Ini实例,创建失败日志会记录但不会抛异常
                ini = createIni(location, false);
                if (!CollectionUtils.isEmpty(ini)) {
                    log.debug("Discovered non-empty INI configuration at location '{}'.  Using for configuration.",
                            location);
                    break;
                }
            }
        }
        return ini;
    }
    // DEFAULT_WEB_INI_RESOURCE_PATH : /WEB-INF/shiro.ini
    // IniFactorySupport.DEFAULT_INI_RESOURCE_PATH :classpath:shiro.ini
    protected String[] getDefaultConfigLocations() {
        return new String[]{
            DEFAULT_WEB_INI_RESOURCE_PATH,
            IniFactorySupport.DEFAULT_INI_RESOURCE_PATH
        };
    }
    // 创建FilterChain包装器
    protected FilterChainResolver createFilterChainResolver() {
        FilterChainResolver resolver = null;
        // 已经setIni过了,因此这里能够取到有效的ini实例
        Ini ini = getIni();
        if (!CollectionUtils.isEmpty(ini)) {
            // 如果ini文件中配置了filters或者urls,创建resolver
            //only create a resolver if the 'filters' or 'urls' sections are defined:
            // 判断ini文件中是否包含urls元素
            Ini.Section urls = ini.getSection(IniFilterChainResolverFactory.URLS);
            // 判断ini文件中是否包含filters元素
            Ini.Section filters = ini.getSection(IniFilterChainResolverFactory.FILTERS);
            // 生成FilterChainResolver实例
            if (!CollectionUtils.isEmpty(urls) || !CollectionUtils.isEmpty(filters)) {
                //either the urls section or the filters section was defined.  Go ahead and create the resolver:
                IniFilterChainResolverFactory factory = new IniFilterChainResolverFactory(ini, this.objects);
                resolver = factory.getInstance();
            }
        }
        // PathMatchingFilterChainResolver
        return resolver;
    }
}  

  objects对象是在父类中定义的
package org.apache.shiro.env;
public class DefaultEnvironment implements NamedObjectEnvironment, Destroyable {
    public static final String DEFAULT_SECURITY_MANAGER_KEY = "securityManager";
    // 这里变量的定义是final
    protected final Map objects;
    private String securityManagerName;
    public DefaultEnvironment() {
        this(new ConcurrentHashMap());
    }
    @SuppressWarnings({"unchecked"})
    public DefaultEnvironment(Map seed) {
        this.securityManagerName = DEFAULT_SECURITY_MANAGER_KEY;
        if (seed == null) {
            throw new IllegalArgumentException("Backing map cannot be null.");
        }
        // final的变量可以在构造方法中进行赋值
        this.objects = (Map) seed;
    }
    // securityManager等对象都会存入到这个objects对象中
}  

  Apache Shiro学习笔记(二)身份验证获取SecurityManager


  •   WebSecurityManager wsm = (WebSecurityManager)factory.getInstance();
      WebIniSecurityManagerFactory类的getInstance方法实际是父类的AbstractFactory的方法

package org.apache.shiro.util;
/**
* TODO - Class JavaDoc
*
* @since 1.0
*/
public abstract class AbstractFactory implements Factory {
    private boolean singleton;
    private T singletonInstance;
    public AbstractFactory() {
        this.singleton = true;
    }
    public boolean isSingleton() {
        return singleton;
    }
    public void setSingleton(boolean singleton) {
        this.singleton = singleton;
    }
    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();
}  


  •   调用子类的IniFactorySupport.createInstance方法

package org.apache.shiro.config;
public abstract class IniFactorySupport extends AbstractFactory {
    public T createInstance() {
        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);
        // 抽象类,需要调用子类的实现
    protected abstract T createDefaultInstance();
}  


  •   子类IniSecurityManagerFactory的createInstance与createDefaultInstance方法

package org.apache.shiro.config;
public class IniSecurityManagerFactory extends IniFactorySupport {
    protected SecurityManager createDefaultInstance() {
        return new DefaultSecurityManager();
    }
    protected SecurityManager createInstance(Ini ini) {
        if (CollectionUtils.isEmpty(ini)) {
            throw new NullPointerException("Ini argument cannot be null or empty.");
        }
        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.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);
    }
     // 同样需要创建SecurityManager的实例
    @SuppressWarnings({"unchecked"})
    private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) {
        // 注意:getInstance方法是由WebIniSecurityManagerFactory触发的,因此这里的createDefaults会先调用子类的createDefaults
        // 与Apache Shiro学习笔记(二)身份验证获取SecurityManager 不一致了
        Map defaults = createDefaults(ini, mainSection);
        Map objects = buildInstances(mainSection, defaults);
        SecurityManager securityManager = getSecurityManagerBean();
        boolean autoApplyRealms = isAutoApplyRealms(securityManager);
        if (autoApplyRealms) {
            //realms and realm factory might have been created - pull them out first so we can
            //initialize the securityManager:
            Collection realms = getRealms(objects);
            //set them on the SecurityManager
            if (!CollectionUtils.isEmpty(realms)) {
                applyRealmsToSecurityManager(realms, securityManager);
            }
        }
        return securityManager;
    }
}  


  •   在父类中还是需要子类的WebIniSecurityManagerFactory.createDefaults方法,在这个方法中会加载Shiro的默认filter

package org.apache.shiro.web.config;
public class WebIniSecurityManagerFactory extends IniSecurityManagerFactory {
    @SuppressWarnings({"unchecked"})
    @Override
    protected Map createDefaults(Ini ini, Ini.Section mainSection) {
        // 调用IniSecurityManagerFactory.createDefaults
        Map defaults = super.createDefaults(ini, mainSection);
        //add the default filters:添加默认的拦截器,如authc、ssl等
        Map defaultFilters = DefaultFilter.createInstanceMap(null);
        defaults.putAll(defaultFilters);
        return defaults;
    }
}  


  •   内置的拦截器基于枚举来实现

package org.apache.shiro.web.filter.mgt;
import org.apache.shiro.util.ClassUtils;
import org.apache.shiro.web.filter.authc.*;
import org.apache.shiro.web.filter.authz.*;
import org.apache.shiro.web.filter.session.NoSessionCreationFilter;
import javax.servlet.Filter;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Enum representing all of the default Shiro Filter instances available to web applications.  Each filter instance is
* typically accessible in configuration the {@link #name() name} of the enum constant.
*
* @since 1.0
*/
public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);
    private final Class

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-636994-1-1.html 上篇帖子: Apache Shiro学习笔记(七)EnvironmentLoaderListener 下篇帖子: python 实现nginx/apache 日志格式的统计脚本
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表