|
鲁春利的工作笔记,好记性不如烂笔头
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 |
|