ShiroFilterFactoryBean中getObject()方法
public Object getObject() throws Exception {
if (instance == null) {
instance = createInstance();
}
return instance;
}
protected AbstractShiroFilter createInstance() throws Exception {
log.debug("Creating Shiro Filter instance.");
SecurityManager securityManager = getSecurityManager();
if (securityManager == null) {
String msg = "SecurityManager property must be set.";
throw new BeanInitializationException(msg);
}
if (!(securityManager instanceof WebSecurityManager)) {
String msg = "The security manager does not implement the WebSecurityManager interface.";
throw new BeanInitializationException(msg);
}
FilterChainManager manager = createFilterChainManager();//创建过滤器链管理器
//Expose the constructed FilterChainManager by first wrapping it in a
// FilterChainResolver implementation. The AbstractShiroFilter implementations
// do not know about FilterChainManagers - only resolvers:
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
//Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
//FilterChainResolver. It doesn't matter that the instance is an anonymous inner class
//here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
//injection of the SecurityManager and FilterChainResolver:
return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}
protected FilterChainManager createFilterChainManager() {
DefaultFilterChainManager manager = new DefaultFilterChainManager();
Map defaultFilters = manager.getFilters();//1
//apply global settings if necessary:
for (Filter filter : defaultFilters.values()) {
applyGlobalPropertiesIfNecessary(filter);
}
//Apply the acquired and/or configured filters:
Map filters = getFilters();
if (!CollectionUtils.isEmpty(filters)) {//把配置的filter加入到manager的filteMap中
for (Map.Entry entry : filters.entrySet()) {
String name = entry.getKey();
Filter filter = entry.getValue();
applyGlobalPropertiesIfNecessary(filter);
if (filter instanceof Nameable) {
((Nameable) filter).setName(name);
}
//'init' argument is false, since Spring-configured filters should be initialized
//in Spring (i.e. 'init-method=blah') or implement InitializingBean:
manager.addFilter(name, filter, false);
}
}
//build up the chains:
Map chains = getFilterChainDefinitionMap();
if (!CollectionUtils.isEmpty(chains)) {
for (Map.Entry entry : chains.entrySet()) {
String url = entry.getKey();
String chainDefinition = entry.getValue();
manager.createChain(url, chainDefinition);//2
}
}
return manager;
}
//1
DefaultFilterChainManager manager = new DefaultFilterChainManager();
DefaultFilterChainManager中
public DefaultFilterChainManager() {
this.filters = new LinkedHashMap();
this.filterChains = new LinkedHashMap();
addDefaultFilters(false);
}
protected void addDefaultFilters(boolean init) {
for (DefaultFilter defaultFilter : DefaultFilter.values()) {
addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
}
}
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);
DefaultFilterChainManager为Map
//2
加入配置的url的过滤器
public void createChain(String chainName, String chainDefinition) {
if (!StringUtils.hasText(chainName)) {
throw new NullPointerException("chainName cannot be null or empty.");
}
if (!StringUtils.hasText(chainDefinition)) {
throw new NullPointerException("chainDefinition cannot be null or empty.");
}
if (log.isDebugEnabled()) {
log.debug("Creating chain [" + chainName + "] from String definition [" + chainDefinition + "]");
}
//parse the value by tokenizing it to get the resulting filter-specific config entries
//
//e.g. for a value of
//
// "authc, roles[admin,user], perms[file:edit]"
//
// the resulting token array would equal
//
// { "authc", "roles[admin,user]", "perms[file:edit]" }
//
String[] filterTokens = splitChainDefinition(chainDefinition);
//each token is specific to each filter.
//strip the name and extract any filter-specific config between brackets [ ]
for (String token : filterTokens) {
String[] nameConfigPair = toNameConfigPair(token);
//now we have the filter name, path and (possibly null) path-specific config. Let's apply them:
addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);//参数 url,roles,admin,user
}
}
public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) {
if (!StringUtils.hasText(chainName)) {
throw new IllegalArgumentException("chainName cannot be null or empty.");
}
Filter filter = getFilter(filterName);
if (filter == null) {
throw new IllegalArgumentException("There is no filter with name '" + filterName +
"' to apply to chain [" + chainName + "] in the pool of available Filters. Ensure a " +
"filter with that name/path has first been registered with the addFilter method(s).");
}
applyChainConfig(chainName, filter, chainSpecificFilterConfig);
NamedFilterList chain = ensureChain(chainName); //得到以url为key的过滤器列表,加入此过滤器
chain.add(filter);
}
protected void applyChainConfig(String chainName, Filter filter, String chainSpecificFilterConfig) {
if (log.isDebugEnabled()) {
log.debug("Attempting to apply path [" + chainName + "] to filter [" + filter + "] " +
"with config [" + chainSpecificFilterConfig + "]");
}
if (filter instanceof PathConfigProcessor) {
((PathConfigProcessor) filter).processPathConfig(chainName, chainSpecificFilterConfig);
//注意,设置了指定过滤器的Map appliedPaths key是url value是中括号里面的角色,权限名
} else {
if (StringUtils.hasText(chainSpecificFilterConfig)) {
//they specified a filter configuration, but the Filter doesn't implement PathConfigProcessor
//this is an erroneous config:
String msg = "chainSpecificFilterConfig was specified, but the underlying " +
"Filter instance is not an 'instanceof' " +
PathConfigProcessor.class.getName() + ". This is required if the filter is to accept " +
"chain-specific configuration.";
throw new ConfigurationException(msg);
}
}
}
public interface PathConfigProcessor {
/**
* Processes the specified {@code config}, unique to the given {@code path}, and returns the Filter that should
* execute for that path/config combination.
*
* @param path the path for which the {@code config} should be applied
* @param config the configuration for the {@code Filter} specific to the given {@code path}
* @return the {@code Filter} that should execute for the given path/config combination.
*/
Filter processPathConfig(String path, String config);
}
可以看到Shiro的web过滤器都实现了此接口
整个过程大致就是:
1、配置ShiroFilterFactoryBean的Map
2、创建SpringShiroFilter过滤器,这个过程需要PathMatchingFilterChainResolver和WebSecurityManager
3、创建 FilterChainManager manager,new出默认的DefaultFilterChainManager(Map
filters加入默认的过滤器,然后根据ShiroFilterFactoryBean的配置修改部分过滤器中的配置,比如loginurl等,
然后会将ShiroFilterFactoryBean中配置的过滤器filters也配置applyGlobalPropertiesIfNecessary ,然后加入到 FilterChainManager的filters中,
接着会解析filterChainDefinitionMap中配置的url与权限的信息(xx.action = authc, roles[admin,user], perms[file:edit])
这个过程呢会创建一个NamedFilterList保存符合条件的过滤器 并将这个list放到filterChains中 key为url
而这个符合条件的过滤器就是根据authc或者roles或者其他你配置的过滤器名称,在filters中查找,并且每个过滤器还会去设置类似admin,user的属性,属性名称为
PathMatchingFilter中的Map
4、显然最后的过滤过程就是 SpringShiroFilter得到请求,然后使用FilterChainManager从filterChains中根据url查找过滤器list,创建新的过滤器链,执行过滤器链