Shiro Essays (2: Discussing FilterChainManager)

Posted by Dean Glass on Sat, 15 Jun 2019 18:30:01 +0200

Happy that I can't write a gorgeous blog post because of my poor writing, I am ready to read 3,000 hidden books, hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee hee heOkay, don't chat much, just go to today's topic.

Code directly:


package org.apache.shiro.web.filter.mgt;

import org.apache.shiro.config.ConfigurationException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import java.util.Map;
import java.util.Set;

/**
 *A FilterChainManager manages the creation and modification of Filter chains from an available pool of Filter instances.
 *This FilterChainManager manages modifications and creation of filter chains from the filter instance pool.
 */
public interface FilterChainManager {


    Map<String, Filter> getFilters();


    NamedFilterList getChain(String chainName);


    boolean hasChains();


    Set<String> getChainNames();


    void addFilter(String name, Filter filter);


    void addFilter(String name, Filter filter, boolean init);


    void createChain(String chainName, String chainDefinition);


    void addToChain(String chainName, String filterName);

    void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) throws ConfigurationException;
}

Seeing the code above, students with experience in web development will soon understand what the various methods should do.But there are many little whites. Let me pick a few ways to talk about them, because there are really several ways to pay attention to and they will be used later.

First: What is the difference between getFilters() and the getChain(String chainName) method?One is to get the set of filters, the other is to get the corresponding filter chain based on chainName.

getFilters(): We know that each filter has its own name, and then we can find the filter by name.In the shiro framework, some default filters are pre-added when FilterChainManager creates instances.The following:

(anon,AnonymousFilter)
(authc,FormAuthenticationFilter)
(authcBasic,BasicHttpAuthenticationFilter)
(logout,LogoutFilter)
(noSessionCreation,NoSessionCreationFilter)
(perms,PermissionsAuthorizationFilter)
(port,PortFilter)
(rest,HttpMethodPermissionFilter)
(roles,RolesAuthorizationFilter)
(ssl,SslFilter)
(user,UserFilter)

These default filters are pre-installed in Map, preceded by the name of the filter, for example: anon is the name of the filter AnonymousFilter, authc is the name of the FormAuthenticationFilter, and so on.Custom filters are added to this map as the project continues to execute.See part of the code for spring-config-shiro.xml as follows:

    <!-- Be based on Form Authentication filters for forms -->
    <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"/>

    <bean id="sysUserFilter" class="com.github.zhangkaitao.shiro.chapter16.web.shiro.filter.SysUserFilter"/>

    <!-- Shiro Of Web Filter -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login"/>
        <property name="filters">
            <util:map>
                <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>

As you can see from the code above, two filters have been customized, one is the FormAuthenticationFilter filter named authc and the other is the SysUserFilter named sysUser.

getChain(String chainName): Gets a NamedFilterList from chainName, which is actually a collection of Lists that are dedicated to one or more filter s.So what is chainName?What is it for?Don't be afraid, let me slow down.In fact, I've used the concept of chainName in the code I posted above.As follows:

More intuitively, these request paths are chainName.The corresponding filters (one or more) are placed in the corresponding NamedFilterList collection.

Next, let's talk about the createChain() method: The official explanation is as follows

Creates a filter chain for the given chainName with the specified chainDefinition String. 

Conventional Use
Because the FilterChainManager interface does not impose any restrictions on filter chain names, (it expects only Strings), a convenient convention is to make the chain name an actual URL path expression (such as an Ant path expression). For example: 
createChain(path_expression, path_specific_filter_chain_definition); This convention can be used by a FilterChainResolver to inspect request URL paths against the chain name (path) and, if a match is found, return the corresponding chain for runtime filtering. 

Chain Definition Format
The chainDefinition method argument is expected to conform to the following format:  filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]
where 
1.filterN is the name of a filter previously registered with the manager, and
2.[optional_configN] is an optional bracketed string that has meaning for that particular filter for this particular chain
If the filter does not need specific config for that chain name/URL path, you may discard the brackets - that is, filterN[] just becomes filterN. 
And because this method does create a chain, remember that order matters! The comma-delimited filter tokens in the chainDefinition specify the chain's execution order. 

Examples
/account/** = authcBasic
This example says "Create a filter named '/account/**' consisting of only the 'authcBasic' filter". Also because the authcBasic filter does not need any path-specific config, it doesn't have any config brackets []. 

/remoting/** = authcBasic, roles[b2bClient], perms["remote:invoke:wan,lan"]
This example by contrast uses the 'roles' and 'perms' filters which do use bracket notation. This definition says: 
Construct a filter chain named '/remoting/**' which 
1.ensures the user is first authenticated (authcBasic) then
2.ensures that user has the b2bClient role, and then finally
3.ensures that they have the remote:invoke:lan,wan permission.

Note: because elements within brackets [ ] can be comma-delimited themselves, you must quote the internal bracket definition if commas are needed (the above example has 'lan,wan'). If we didn't do that, the parser would interpret the chain definition as four tokens: 
1.authcBasic
2.roles[b2bclient]
3.perms[remote:invoke:lan
4.wan]
which is obviously incorrect. So remember to use quotes if your internal bracket definitions need to use commas.

Okay, let me translate it.Despicable English water is limited, so it is inevitable to make mistakes. Please understand and leave behind your valuable corrections.

Create a filter chain for a given chainName with a chainDefinition string.

The FilterChainManager interface does not impose some restrictions on the name of the filter chain, only strings are expected.A convenient convention is to have chain name s conform to url-path expressions, such as Ant-style path expressions.
This convention allows FilterChainResolver to check the url path of the request against the chain name and, if matched, return the corresponding filter chain.

The parameters of the chainDefinition method should conform to the following format:
filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]. 
This "filter N" is the name of a filter that has previously been registered with the FilterChainManager.
This [optional_configN] is an optional bracketed string for those specific strings on this filter chain.
If this filter is not configured on the url path of this chain name, then filterN[] is equivalent to filterN.
Because this method creates a filter chain, remember the importance of this order.
Comma-separated filter tokens on the chain definition specify the order in which the filter chain is executed.
I feel a mess in translation myself, just look at the examples.)

For example: /login = authc,role[devil].
'/login'is what chain name has said before,'=' followed by chainDefinition, or'authc,role[devil]', commas separate the filters.
Use String's split method to get a String array.String[0]=authc,String[1]=role[devil], so the filter chain execution order given by the official document is to execute a filter with the name authc first and a filter with the name role second.
You have noticed the role[devil], which has the parameter devil in parentheses and is called chainSpecificFilterConfig in the shiro framework.
Now, for example, if this filter handles role functionality, only users of the devil role will have access to the resources under that path.

note: Expand from a point of knowledge here. In a custom filter, if you want to use this parenthesized function, such as role[devil], your custom filter must implement the PathConfigProcessor interface

FilterChainManager is an abstract interface that has been implemented in the shiro framework in web development.

DefaultFilterChainManager implements this interface.

 

This is the first introduction to the FilterChainManager interface.Let's explore its initialization process.

In a previous blog post: ShiroFilterFactoryBean has been mentioned in shiro's article (how spring associates with Shiro in the filter configuration of 1:web.xml), which is exactly how it initializes the FilterChainManager, since it is the entrance to shiro, so it must be responsible for it.Find the createFilterChainManager() method for this class, as shown below:

As mentioned in the shiro article (how spring relates to shiro in the filter configuration in 1:web.xml), the

The org.springframework.web.filter.DelegatingFilterProxy is called layer by layer.

Until you call the getObject() method of org.apache.shiro.spring.web.ShiroFilterFactoryBean, take a look at this method

    public Object getObject() throws Exception {
        if (instance == null) {
            instance = createInstance();
        }
        return instance;
    }

Next, go back and call the createInstance() method:

Okay, that's it for today. Wow, it's 11 p.m. It's time to wash and sleep.You are still struggling in the middle of the night, I wish you all the best!If this article can help you, please reprint it and indicate the source.

Topics: Shiro Apache Spring xml