Apache Shiro???????????????SecurityManager?????????

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Apache Shiro???????????????SecurityManager?????????相关的知识,希望对你有一定的参考价值。

?????????ror   ??????   ?????????   deb   fir   cto   scanner   transient   select   

??????Shiro(v1.2+)???SecurityManager??????????????????????????????????????????????????????main?????????????????????

Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();

???????????????classpath????????????shiro.ini???????????????SecurityManager????????????web?????????????????????????????????????????????????????????????????????

???web?????????????????????????????????Listener??????SecurityManager???????????????Listener???????????????????????????Listener???shrio-web.jar??????

<listener>
        <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

EnvironmentLoaderListener???????????????????????????????????????
????????????

EnvironmentLoader????????????????????????????????????????????????????????????Shiro????????????org.apache.shiro.web.mgt.WebSecurityManager?????????ServletContext??????

????????????Shiro??????????????????web.xml????????????????????????????????????shiroEnvironmentClass?????????shiroConfigLocations???????????????Shiro????????????????????????????????????????????????????????????????????????????????????

shiroEnvironmentClass??????????????????WebEnvironment?????????????????????????????????IniWebEnvironment???
shiroConfigLocations?????????shiro?????????????????????????????????????????????????????????/WEB-INF/shiro.ini???????????????????????????classpath:shiro.ini???

public class EnvironmentLoaderListener extends EnvironmentLoader implements ServletContextListener {

    /**
     * Initializes the Shiro {@code WebEnvironment} and binds it to the {@code ServletContext} at application
     * startup for future reference.
     *
     * @param sce the ServletContextEvent triggered upon application startup
     */
    public void contextInitialized(ServletContextEvent sce) {
        initEnvironment(sce.getServletContext());
    }

    /**
     * Destroys any previously created/bound {@code WebEnvironment} instance created by
     * the {@link #contextInitialized(javax.servlet.ServletContextEvent)} method.
     *
     * @param sce the ServletContextEvent triggered upon application shutdown
     */
    public void contextDestroyed(ServletContextEvent sce) {
        destroyEnvironment(sce.getServletContext());
    }
}
public class EnvironmentLoader {
    public WebEnvironment initEnvironment(ServletContext servletContext) throws IllegalStateException {

        if (servletContext.getAttribute(ENVIRONMENT_ATTRIBUTE_KEY) != null) {
            String msg = "There is already a Shiro environment associated with the current ServletContext.  " +
                    "Check if you have multiple EnvironmentLoader* definitions in your web.xml!";
            throw new IllegalStateException(msg);
        }

        servletContext.log("Initializing Shiro environment");
        log.info("Starting Shiro environment initialization.");

        long startTime = System.currentTimeMillis();

        try {

            WebEnvironment environment = createEnvironment(servletContext);
            servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY,environment);

            log.debug("Published WebEnvironment as ServletContext attribute with name [{}]",
                    ENVIRONMENT_ATTRIBUTE_KEY);

            if (log.isInfoEnabled()) {
                long elapsed = System.currentTimeMillis() - startTime;
                log.info("Shiro environment initialized in {} ms.", elapsed);
            }

            return environment;
        } catch (RuntimeException ex) {
            log.error("Shiro environment initialization failed", ex);
            servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, ex);
            throw ex;
        } catch (Error err) {
            log.error("Shiro environment initialization failed", err);
            servletContext.setAttribute(ENVIRONMENT_ATTRIBUTE_KEY, err);
            throw err;
        }
    }

    protected WebEnvironment createEnvironment(ServletContext sc) {

        //??????WebEnvironment???????????????????????????
        WebEnvironment webEnvironment = determineWebEnvironment(sc);
        if (!MutableWebEnvironment.class.isInstance(webEnvironment)) {
            throw new ConfigurationException("Custom WebEnvironment class [" + webEnvironment.getClass().getName() +
                    "] is not of required type [" + MutableWebEnvironment.class.getName() + "]");
        }

        String configLocations = sc.getInitParameter(CONFIG_LOCATIONS_PARAM);
        boolean configSpecified = StringUtils.hasText(configLocations);

        if (configSpecified && !(ResourceConfigurable.class.isInstance(webEnvironment))) {
            String msg = "WebEnvironment class [" + webEnvironment.getClass().getName() + "] does not implement the " +
                    ResourceConfigurable.class.getName() + "interface.  This is required to accept any " +
                    "configured " + CONFIG_LOCATIONS_PARAM + "value(s).";
            throw new ConfigurationException(msg);
        }

        MutableWebEnvironment environment = (MutableWebEnvironment) webEnvironment;
        //???????????????ServletContext??????
        environment.setServletContext(sc);

        //?????????web.xml???????????????????????????????????????????????????environment???
        if (configSpecified && (environment instanceof ResourceConfigurable)) {
            ((ResourceConfigurable) environment).setConfigLocations(configLocations);
        }

        //??????????????????????????????
        customizeEnvironment(environment);

        //??????environment???init???????????????environment??????
        LifecycleUtils.init(environment);

        return environment;
    }

    protected WebEnvironment determineWebEnvironment(ServletContext servletContext) {

        //???ServletContext??????????????????WebEnvironment?????????--shiroEnvironmentClass?????????????????????????????????
        Class<? extends WebEnvironment> webEnvironmentClass = webEnvironmentClassFromServletContext(servletContext);
        WebEnvironment webEnvironment = null;

        // ????????????Java???ServiceLoader?????????WebEnvironment????????????
        if (webEnvironmentClass == null) {
            webEnvironment = webEnvironmentFromServiceLoader();
        }

        // ??????????????????????????????????????????????????????WebEnvironment?????????IniWebEnvironment
        if (webEnvironmentClass == null && webEnvironment == null) {
            webEnvironmentClass = getDefaultWebEnvironmentClass();
        }

        // ??????WebEnvironment?????????
        if (webEnvironmentClass != null) {
            webEnvironment = (WebEnvironment) ClassUtils.newInstance(webEnvironmentClass);
        }

        return webEnvironment;
    }

    private WebEnvironment webEnvironmentFromServiceLoader() {

        WebEnvironment webEnvironment = null;
        /*
         * ??????Java???ServiceLoader???????????????WebEnvironment????????????(??????jar??????META-INF??????services?????????????????????)???
         * ???????????????services????????????????????????org.apache.shiro.web.env.WebEnvironment???????????????????????????????????????WebEnvironment????????????????????????
         * ??????????????????????????????????????????????????????????????????????????????
         * */
        ServiceLoader<WebEnvironment> serviceLoader = ServiceLoader.load(WebEnvironment.class);
        Iterator<WebEnvironment> iterator = serviceLoader.iterator();

        // ??????????????????????????????
        if (iterator.hasNext()) {
            webEnvironment = iterator.next();
        }
        // ??????????????????????????????????????????
        if (iterator.hasNext()) {
            List<String> allWebEnvironments = new ArrayList<String>();
            allWebEnvironments.add(webEnvironment.getClass().getName());
            while (iterator.hasNext()) {
                allWebEnvironments.add(iterator.next().getClass().getName());
            }
            throw new ConfigurationException("ServiceLoader for class [" + WebEnvironment.class + "] returned more then one " +
                    "result.  ServiceLoader must return zero or exactly one result for this class. Select one using the " +
                    "servlet init parameter ???"+ ENVIRONMENT_CLASS_PARAM +"???. Found: " + allWebEnvironments);
        }
        return webEnvironment;
    }
}

?????????????????????WebEnvironment?????????????????????????????????
1??????ServletContext??????????????????
2??????jar??????????????????
3??????????????????IniWebEnvironment

?????????WebEnvironment?????????????????????????????????????????????????????????init??????????????????????????????????????????IniWebEnvironment???

public class IniWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable {

    public static final String DEFAULT_WEB_INI_RESOURCE_PATH = "/WEB-INF/shiro.ini";
    public static final String FILTER_CHAIN_RESOLVER_NAME = "filterChainResolver";

    private static final Logger log = LoggerFactory.getLogger(IniWebEnvironment.class);

    /**
     * The Ini that configures this WebEnvironment instance.
     */
    private Ini ini;

    private WebIniSecurityManagerFactory factory;

    public IniWebEnvironment() {
        //?????????WebIniSecurityManagerFactory??????
        factory = new WebIniSecurityManagerFactory();
    }

    /**
     * ??????????????????
     */
    public void init() {
        //??????shiiro.ini??????????????????????????????Ini??????
        setIni(parseConfig());

        //??????Ini???????????????WebIniSecurityManagerFactory??????WebSecurityManager??????
        configure();
    }
}

protected Ini parseConfig() {
        //?????????????????????????????????null
        Ini ini = getIni();

        //????????????????????????????????????????????????web.xml??????????????????,?????????????????????????????????EnvironmentLoader????????????
        String[] configLocations = getConfigLocations();

        if (log.isWarnEnabled() && !CollectionUtils.isEmpty(ini) &&
                configLocations != null && configLocations.length > 0) {
            //??????Ini????????????????????????configLocations????????????,??????????????????
            log.warn("Explicit INI instance has been provided, but configuration locations have also been " +
                    "specified.  The {} implementation does not currently support multiple Ini config, but this may " +
                    "be supported in the future. Only the INI instance will be used for configuration.",
                    IniWebEnvironment.class.getName());
        }

        if (CollectionUtils.isEmpty(ini)) {
            log.debug("Checking any specified config locations.");
            //??????????????????????????????????????????Ini??????
            ini = getSpecifiedIni(configLocations);
        }

        if (CollectionUtils.isEmpty(ini)) {
            log.debug("No INI instance or config locations specified.  Trying default config locations.");
            /*
             * ???????????????web.xml?????????????????????????????????????????????????????????????????????
             * 1,/WEB-INF/shiro.ini
             * 2,classpath:shiro.ini
             * */
            ini = getDefaultIni();
        }

        /*
         * ?????????????????????????????????getFrameworkIni???????????????Ini???????????????????????????Ini????????????.
         * getFrameworkIni?????????????????????null????????????????????????????????????????????????Ini??????
         * */
        ini = mergeIni(getFrameworkIni(), ini);

        if (CollectionUtils.isEmpty(ini)) {
            String msg = "Shiro INI configuration was either not found or discovered to be empty/unconfigured.";
            throw new ConfigurationException(msg);
        }
        return ini;
    }

        /**
     * ????????????????????????Ini????????????
     * */
    protected Ini createIni(String configLocation, boolean required) throws ConfigurationException {

        Ini ini = null;

        if (configLocation != null) {
            ini = convertPathToIni(configLocation, required);
        }
        if (required && CollectionUtils.isEmpty(ini)) {
            String msg = "Required configuration location ???" + configLocation + "??? does not exist or did not " +
                    "contain any INI configuration.";
            throw new ConfigurationException(msg);
        }

        return ini;
    }

        /**
     * ????????????????????????????????????????????????????????????????????????Ini???????????????load??????????????????Ini??????
     * */
    private Ini convertPathToIni(String path, boolean required) {

        Ini ini = null;

        if (StringUtils.hasText(path)) {
            InputStream is = null;

            //SHIRO-178: Check for servlet context resource and not only resource paths:
            if (!ResourceUtils.hasResourcePrefix(path)) {
                is = getServletContextResourceStream(path);
            } else {
                try {
                    is = ResourceUtils.getInputStreamForPath(path);
                } catch (IOException e) {
                    if (required) {
                        throw new ConfigurationException(e);
                    } else {
                        if (log.isDebugEnabled()) {
                            log.debug("Unable to load optional path ???" + path + "???.", e);
                        }
                    }
                }
            }
            if (is != null) {
                ini = new Ini();
                ini.load(is);
            } else {
                if (required) {
                    throw new ConfigurationException("Unable to load resource path ???" + path + "???");
                }
            }
        }

        return ini;
    }

?????????Ini????????????????????????

public class Ini implements Map<String, Ini.Section> {
    private static transient final Logger log = LoggerFactory.getLogger(Ini.class);

    public static final String DEFAULT_SECTION_NAME = ""; //empty string means the first unnamed section
    public static final String DEFAULT_CHARSET_NAME = "UTF-8";

    public static final String COMMENT_POUND = "#";
    public static final String COMMENT_SEMICOLON = ";";
    public static final String SECTION_PREFIX = "[";
    public static final String SECTION_SUFFIX = "]";

    protected static final char ESCAPE_TOKEN = ???\???;

    private final Map<String, Section> sections;

    /**
     * Creates a new empty {@code Ini} instance.
     */
    public Ini() {
        this.sections = new LinkedHashMap<String, Section>();
    }

    public void load(InputStream is) throws ConfigurationException {
        if (is == null) {
            throw new NullPointerException("InputStream argument cannot be null.");
        }
        InputStreamReader isr;
        try {
            isr = new InputStreamReader(is, DEFAULT_CHARSET_NAME);
        } catch (UnsupportedEncodingException e) {
            throw new ConfigurationException(e);
        }
        load(isr);
    }

    public void load(Reader reader) {
        Scanner scanner = new Scanner(reader);
        try {
            load(scanner);
        } finally {
            try {
                scanner.close();
            } catch (Exception e) {
                log.debug("Unable to cleanly close the InputStream scanner.  Non-critical - ignoring.", e);
            }
        }
    }

        public void load(Scanner scanner) {

        String sectionName = DEFAULT_SECTION_NAME;
        StringBuilder sectionContent = new StringBuilder();

        //?????????????????????
        while (scanner.hasNextLine()) {

            String rawLine = scanner.nextLine();
            //?????????????????????
            String line = StringUtils.clean(rawLine);

            if (line == null || line.startsWith(COMMENT_POUND) || line.startsWith(COMMENT_SEMICOLON)) {
                //?????????????????????
                continue;
            }
            //??????section?????????????????? [main] ????????????????????????main???
            String newSectionName = getSectionName(line);
            if (newSectionName != null) {
                //??????section????????????????????????????????????section??????
                addSection(sectionName, sectionContent);

                //????????????section??????StringBuilder????????????????????????section???????????????
                sectionContent = new StringBuilder();

                sectionName = newSectionName;

                if (log.isDebugEnabled()) {
                    log.debug("Parsing " + SECTION_PREFIX + sectionName + SECTION_SUFFIX);
                }
            } else {
                //??????????????????
                sectionContent.append(rawLine).append("
");
            }
        }

        //??????Section???????????????
        addSection(sectionName, sectionContent);
    }

    private void addSection(String name, StringBuilder content) {
        if (content.length() > 0) {
            String contentString = content.toString();
            String cleaned = StringUtils.clean(contentString);
            if (cleaned != null) {
                //??????Section???????????????????????????
                Section section = new Section(name, contentString);
                if (!section.isEmpty()) {
                    //???????????????????????????Section??????
                    sections.put(name, section);
                }
            }
        }
    }

    public static class Section implements Map<String, String> {
            private final String name;
            private final Map<String, String> props;

            /*
         * ??????????????????????????????????????????????????????props?????????
         * */
        private Section(String name, String sectionContent) {
            if (name == null) {
                throw new NullPointerException("name");
            }
            this.name = name;
            Map<String,String> props;
            if (StringUtils.hasText(sectionContent) ) {
                props = toMapProps(sectionContent);
            } else {
                props = new LinkedHashMap<String,String>();
            }
            if ( props != null ) {
                this.props = props;
            } else {
                this.props = new LinkedHashMap<String,String>();
            }
        }

    }
}

????????????IniWebEnvironment??????????????????????????????????????????Ini?????????????????????????????????????????????????????????Section????????????????????????????????????Ini???????????????WebSecurityManager?????????????????????IniWebEnvironment ???configure??????

public class IniWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable {
    protected void configure() {
        //Map<String, Object>??????
        this.objects.clear();

        WebSecurityManager securityManager = createWebSecurityManager();
        setWebSecurityManager(securityManager);

        FilterChainResolver resolver = createFilterChainResolver();
        if (resolver != null) {
            setFilterChainResolver(resolver);
        }
    }

    protected Map<String, Object> getDefaults() {
        Map<String, Object> defaults = new HashMap<String, Object>();
        defaults.put(FILTER_CHAIN_RESOLVER_NAME, new IniFilterChainResolverFactory());
        return defaults;
    }

    protected WebSecurityManager createWebSecurityManager() {
        //??????????????????Ini??????
        Ini ini = getIni();
        if (!CollectionUtils.isEmpty(ini)) {
            factory.setIni(ini);
        }

        Map<String, Object> defaults = getDefaults();
        if (!CollectionUtils.isEmpty(defaults)) {
            factory.setDefaults(defaults);
        }
        //???WebIniSecurityManagerFactory???????????????WebSecurityManager
        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<String, ?> beans = factory.getBeans();
        if (!CollectionUtils.isEmpty(beans)) {
            this.objects.putAll(beans);
        }

        return wsm;
    }
}

????????????WebIniSecurityManagerFactory???getInstance???????????????

????????????

????????????????????????getInstance??????????????????????????????????????????AbstractFactory??????getInstance??????

public abstract class AbstractFactory<T> implements Factory<T> {
    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;
    }
     /*
     * ??????(IniFactorySupport)???????????????????????????
     * */
    protected abstract T createInstance();
}
public abstract class IniFactorySupport<T> extends AbstractFactory<T> {
    public T createInstance() {
        /*
         * ??????Ini????????????????????????????????????
         * ??????ini???????????????????????????????????????????????????Ini??????
         * */
        Ini ini = resolveIni();

        T instance;

        if (CollectionUtils.isEmpty(ini)) { 
            //??????Ini?????????????????????????????????(IniSecurityManagerFactory)???????????????SecurityManager????????????
            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 + "]");
            //????????????(IniSecurityManagerFactory)?????????Ini????????????????????????SecurityManager??????
            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();
}
public class IniSecurityManagerFactory extends IniFactorySupport<SecurityManager> {
    public static final String MAIN_SECTION_NAME = "main";

    public static final String SECURITY_MANAGER_NAME = "securityManager";
    public static final String INI_REALM_NAME = "iniRealm";

    private ReflectionBuilder builder;

    public IniSecurityManagerFactory() {
        this.builder = new ReflectionBuilder();
    }

    //?????????SecurityManager??????????????????WebIniSecurityManagerFactory?????????????????????DefaultWebSecurityManager???
    protected SecurityManager createDefaultInstance() {
        return new DefaultSecurityManager();
    }

    //??????Ini?????????SecurityManager??????
    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) {
        return createSecurityManager(ini, getConfigSection(ini));
    }

    //??????[main]???????????????????????????????????????????????????
    private Ini.Section getConfigSection(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 mainSection;
    }

    @SuppressWarnings({"unchecked"})
    private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) {
        /*
         * ?????????createDefaults?????????WebIniSecurityManagerFactory?????????
         * ????????????????????????????????????createDefaults???????????????????????????????????????????????????Filter?????????
         * 
         * ????????????????????????ReflectionBuilder?????????objects???Map?????????????????????????????????????????????SecurityManager???Realm??????????????????Filter?????????
         * 
         * ?????????createDefaults?????????Map????????????ReflectionBuilder?????????objects???Map???????????????
         * */
        getReflectionBuilder().setObjects(createDefaults(ini, mainSection));

        //??????ReflectionBuilder?????????????????????????????????????????????objects???????????????????????????????????????init??????,????????????objects?????????
        Map<String, ?> objects = buildInstances(mainSection);

        //?????????ReflectionBuilder???????????????SecurityManager???????????????
        SecurityManager securityManager = getSecurityManagerBean();

        /*
         * ??????securityManager??????RealmSecurityManager???????????????true???
         * ?????????RealmSecurityManager???????????????????????????Realm??????????????????true???
         * ????????????false
         * */
        boolean autoApplyRealms = isAutoApplyRealms(securityManager);

        if (autoApplyRealms) {
            //???????????????Realms?????????Realm???RealmFactory?????????
            Collection<Realm> realms = getRealms(objects);

            if (!CollectionUtils.isEmpty(realms)) {
                //??????securityManager??????RealmSecurityManager?????????????????????????????????securityManager??????Realms
                applyRealmsToSecurityManager(realms, securityManager);
            }
        }
        return securityManager;
    }
}

?????????SecurityManager?????????????????????????????????IniWebEnvironment?????????objects[Map]???

public class IniWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable {
    protected void configure() {

        //Map<String, Object>??????
        this.objects.clear();

        WebSecurityManager securityManager = createWebSecurityManager();
        setWebSecurityManager(securityManager);

        //??????shiro.ini?????????????????????filters??? ??? ???urls?????????Filter?????????objects?????????
        FilterChainResolver resolver = createFilterChainResolver();
        if (resolver != null) {
            setFilterChainResolver(resolver);
        }
    }
}

?????????Shiro??????????????????????????????EnvironmentLoaderListener ???????????????IniWebEnvironment???????????????ServletContext?????????????????????

??????????????????

???????????????????????????EnvironmentLoaderListener????????????????????????WebEnvironment???????????????????????????????????????ServletContext???

1?????????WebEnvironment??????
1?????????web.xml?????????????????????shiroEnvironmentClass
2?????????ServiceLoader????????????jar???????????????
3??????????????????IniWebEnvironment??????

2?????????WebEnvironment???init???????????????WebEnvironment??????
??????WebEnvironment???????????????????????????WebIniSecurityManagerFactory??????factory???
1???????????????????????????????????????shiro.ini????????????Ini??????
2??????Ini???????????????factory???ini??????
3???????????????IniFilterChainResolverFactory?????????factory???defaultBeans(Map)??????
4?????????factory???getInstance????????????SecurityManager??????
--??????Ini??????????????????????????????Realm?????????????????????SecurityManager??????
5??????SecurityManager?????????objects(Map)?????????WebEnvironment???objects??????

?????????SecurityManager??? DefaultWebSecurityManager

?????????????????????Session???Realm?????????

以上是关于Apache Shiro???????????????SecurityManager?????????的主要内容,如果未能解决你的问题,请参考以下文章

shiro学习一

转Apache shiro集群实现 shiro入门介绍

Apache shiro集群实现

Apache Shiro 使用手册Shiro架构介绍

Apache Shiro 使用手册Shiro架构介绍

Apache Shiro 使用手册Shiro 认证