I. configuration
<!-- Shiro Of Web filter --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- Injection Security Manager--> <property name="securityManager" ref="securityManager"/> <!-- Set up login URL--> <property name="loginUrl" value="/login"/> <property name="filters"> <util:map> <!-- register authc and sysUser--> <entry key="authc" value-ref="formAuthenticationFilter"/> <entry key="sysUser" value-ref="sysUserFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /login = authc /logout = logout /authenticated = authc /** = user,sysUser </value> </property> </bean>
II. Filter chain definitions where the node is injected
The setFilterChainDefinitions method of ShiroFilterFactoryBean will inject the filter chain definition as follows:
public void setFilterChainDefinitions(String definitions) { Ini ini = new Ini(); ini.load(definitions); Section section = ini.getSection("urls"); if (CollectionUtils.isEmpty(section)) { section = ini.getSection(""); } this.setFilterChainDefinitionMap(section); }
After executing the above code, the value of section is as follows:
section = {Ini$Section@5444} size = 4 "/login" -> "authc" "/logout" -> "logout" "/authenticated" -> "authc" "/**" -> "user,sysUser"
At the same time, the variable filterChainDefinitionMap of ShiroFilterFactoryBean becomes the following
filterChainDefinitionMap = {Ini$Section@5444} size = 4 "/login" -> "authc" "/logout" -> "logout" "/authenticated" -> "authc" "/**" -> "user,sysUser"
3. filters where the node is injected
public void setFilters(Map<String, Filter> filters) { this.filters = filters; }
What it looks like after injection:
this = {ShiroFilterFactoryBean@5425} securityManager = {DefaultWebSecurityManager@5428} filters = {LinkedHashMap@5426} size = 2 "authc" -> {FormAuthenticationFilter@5436} "org.apache.shiro.web.filter.authc.FormAuthenticationFilter@3435b6d8" "sysUser" -> {SysUserFilter@5438} "com.github.cakin.shiro.chapter16.web.shiro.filter.SysUserFilter@13553828"
IV. protected FilterChainManager createFilterChainManager() after finishing the work
manager = {DefaultFilterChainManager@5681} filterConfig = null filters = {LinkedHashMap@5682} size = 12 "anon" -> {AnonymousFilter@5698} "anon" "authc" -> {FormAuthenticationFilter@5751} "authc" "authcBasic" -> {BasicHttpAuthenticationFilter@5702} "authcBasic" "logout" -> {LogoutFilter@5704} "logout" "noSessionCreation" -> {NoSessionCreationFilter@5706} "noSessionCreation" "perms" -> {PermissionsAuthorizationFilter@5708} "perms" "port" -> {PortFilter@5710} "port" "rest" -> {HttpMethodPermissionFilter@5712} "rest" "roles" -> {RolesAuthorizationFilter@5714} "roles" "ssl" -> {SslFilter@5716} "ssl" "user" -> {UserFilter@5718} "user" "sysUser" -> {SysUserFilter@5862} "sysUser" filterChains = {LinkedHashMap@5683} size = 4 "/login" -> {SimpleNamedFilterList@6101} size = 1 "/logout" -> {SimpleNamedFilterList@6103} size = 1 "/authenticated" -> {SimpleNamedFilterList@6105} size = 1 "/**" -> {SimpleNamedFilterList@6107} size = 2
filters: the default filter plus the filter registered in the configuration file.
filterChains: the configuration value in the configuration file.
V. AbstractShiroFilter analysis
1. If you add a breakpoint to the executeChain function, click http://localhost:8080/chapter16/ After the method runs, the variables are as follows:
chain = {ProxiedFilterChain@6960} orig = {ServletHandler$CachedChain@6959} "spring" filters = {SimpleNamedFilterList@6107} size = 2 0 = {UserFilter@5718} "user" 1 = {SysUserFilter@5862} "sysUser" index = 0
The call is as follows:
executeChain:449, AbstractShiroFilter (org.apache.shiro.web.servlet) call:365, AbstractShiroFilter$1 (org.apache.shiro.web.servlet) doCall:90, SubjectCallable (org.apache.shiro.subject.support) call:83, SubjectCallable (org.apache.shiro.subject.support) execute:383, DelegatingSubject (org.apache.shiro.subject.support) doFilterInternal:362, AbstractShiroFilter (org.apache.shiro.web.servlet) doFilter:125, OncePerRequestFilter (org.apache.shiro.web.servlet) invokeDelegate:344, DelegatingFilterProxy (org.springframework.web.filter) doFilter:261, DelegatingFilterProxy (org.springframework.web.filter)
2. From the above analysis, the user filter and SysUserFilter will be used
UserFilter will go to the following functions
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { if (isLoginRequest(request, response)) { return true; } else { Subject subject = getSubject(request, response); // If principal is not null, then the user is known and should be allowed access. return subject.getPrincipal() != null; } }
When you go to isAccessAllowed, its call stack is as follows:
isAccessAllowed:50, UserFilter (org.apache.shiro.web.filter.authc) onPreHandle:162, AccessControlFilter (org.apache.shiro.web.filter) isFilterChainContinued:203, PathMatchingFilter (org.apache.shiro.web.filter) preHandle:178, PathMatchingFilter (org.apache.shiro.web.filter) doFilterInternal:131, AdviceFilter (org.apache.shiro.web.servlet) doFilter:125, OncePerRequestFilter (org.apache.shiro.web.servlet) doFilter:66, ProxiedFilterChain (org.apache.shiro.web.servlet) executeChain:449, AbstractShiroFilter (org.apache.shiro.web.servlet) call:365, AbstractShiroFilter$1 (org.apache.shiro.web.servlet) doCall:90, SubjectCallable (org.apache.shiro.subject.support) call:83, SubjectCallable (org.apache.shiro.subject.support) execute:383, DelegatingSubject (org.apache.shiro.subject.support) doFilterInternal:362, AbstractShiroFilter (org.apache.shiro.web.servlet) doFilter:125, OncePerRequestFilter (org.apache.shiro.web.servlet) invokeDelegate:344, DelegatingFilterProxy (org.springframework.web.filter) doFilter:261, DelegatingFilterProxy (org.springframework.web.filter)
SysUserFilter will go to the following functions
protected boolean onPreHandle( ServletRequest request, ServletResponse response, Object mappedValue ) { // Get user information String username = (String) SecurityUtils.getSubject().getPrincipal(); // Set user information to the "user" attribute request.setAttribute(Constants.CURRENT_USER, userService.findByUsername(username)); return true; }
When you go to the function onPreHandle, its call stack is as follows:
onPreHandle:38, SysUserFilter (com.github.cakin.shiro.chapter16.web.shiro.filter) isFilterChainContinued:203, PathMatchingFilter (org.apache.shiro.web.filter) preHandle:178, PathMatchingFilter (org.apache.shiro.web.filter) doFilterInternal:131, AdviceFilter (org.apache.shiro.web.servlet) doFilter:125, OncePerRequestFilter (org.apache.shiro.web.servlet) doFilter:66, ProxiedFilterChain (org.apache.shiro.web.servlet) executeChain:108, AdviceFilter (org.apache.shiro.web.servlet) doFilterInternal:137, AdviceFilter (org.apache.shiro.web.servlet) doFilter:125, OncePerRequestFilter (org.apache.shiro.web.servlet) doFilter:66, ProxiedFilterChain (org.apache.shiro.web.servlet) executeChain:449, AbstractShiroFilter (org.apache.shiro.web.servlet) call:365, AbstractShiroFilter$1 (org.apache.shiro.web.servlet) doCall:90, SubjectCallable (org.apache.shiro.subject.support) call:83, SubjectCallable (org.apache.shiro.subject.support) execute:383, DelegatingSubject (org.apache.shiro.subject.support) doFilterInternal:362, AbstractShiroFilter (org.apache.shiro.web.servlet) doFilter:125, OncePerRequestFilter (org.apache.shiro.web.servlet) invokeDelegate:344, DelegatingFilterProxy (org.springframework.web.filter) doFilter:261, DelegatingFilterProxy (org.springframework.web.filter)
We can analyze the runtime call from the call stack.