创建核心Filter
同其他框架一样,都有个切入点,这个核心Filter就是拦截所有请求的。
通过web.xml中配置的Filer进入,执行init方法获取这个instance,调用下面的createInstance方法创建核心Filter:
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);}
createFilterChainManager方法比较重要,包含以下必要操作:
-
DefaultFilterChainManager对象的创建
-
defaultFilters的获取和相关url的填充
-
自定义filters的获取和相关url的填充
-
获取FilterChainDefinitionMap (这个就是配置文件中的filterChainDefinitions的映射关系)
- 对url和权限的映射关系作处理
默认的DefaultFilter枚举中包含以下filter类:
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);
执行doFilter方法
看下内部类 SpringShiroFilter:
private static final class SpringShiroFilter extends AbstractShiroFilter { protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) { super(); if (webSecurityManager == null) { throw new IllegalArgumentException("WebSecurityManager property cannot be null."); } setSecurityManager(webSecurityManager); if (resolver != null) { setFilterChainResolver(resolver); } }}
在org.apache.shiro.web.servlet.OncePerRequestFilter中实现了doFilter方法:
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException { String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName(); if ( request.getAttribute(alreadyFilteredAttributeName) != null ) { log.trace("Filter '{}' already executed. Proceeding without invoking this filter.", getName()); filterChain.doFilter(request, response); } else //noinspection deprecation if (/* added in 1.2: */ !isEnabled(request, response) || /* retain backwards compatibility: */ shouldNotFilter(request) ) { log.debug("Filter '{}' is not enabled for the current request. Proceeding without invoking this filter.", getName()); filterChain.doFilter(request, response); } else { // Do invoke this filter... log.trace("Filter '{}' not yet executed. Executing now.", getName()); request.setAttribute(alreadyFilteredAttributeName, Boolean.TRUE); try { doFilterInternal(request, response, filterChain); } finally { // Once the request has finished, we're done and we don't // need to mark as 'already filtered' any more. request.removeAttribute(alreadyFilteredAttributeName); } }}
三种情况,分为两条路线:
1. filterChain.doFilter(request, response); 直接放行 2. doFilterInternal(request, response, filterChain); 走子类实现在org.apache.shiro.web.servlet.AbstractShiroFilter实现doFilterInternal:
protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) throws ServletException, IOException { Throwable t = null; try { final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain); final ServletResponse response = prepareServletResponse(request, servletResponse, chain); final Subject subject = createSubject(request, response); //noinspection unchecked subject.execute(new Callable() { public Object call() throws Exception { updateSessionLastAccessTime(request, response); executeChain(request, response, chain); return null; } }); } catch (ExecutionException ex) { t = ex.getCause(); } catch (Throwable throwable) { t = throwable; } if (t != null) { if (t instanceof ServletException) { throw (ServletException) t; } if (t instanceof IOException) { throw (IOException) t; } //otherwise it's not one of the two exceptions expected by the filter method signature - wrap it in one: String msg = "Filtered request failed."; throw new ServletException(msg, t); }}
将HttpServletRequest和HttpServletResponse包装成shiro自己的ShiroHttpServletRequest和ShiroHttpServletResponse。
利用包装后的对象创建Subject。
然后是执行subject的execute的方法。
protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) throws IOException, ServletException { FilterChain chain = getExecutionChain(request, response, origChain); chain.doFilter(request, response);}
获取的FilterChain是一个代理的ProxiedFilterChain,持有自己的Filter集合,重写doFilter方法:取自己持有的Filter集合,一个个执行其doFilter方法,当所有的Filter都执行完后,再执行servlet的FilterChain。
后面的过程就是一个原始的FilterChain的执行过程。
可以想象,原生的Filter链似乎也是这样一个执行过程,遍历web.xml中配置的所有Filter。
整个过程就是代理模式的运用。