Shiro源碼分析-ShiroFilterFactoryBean


Shiro源碼分析-ShiroFilterFactoryBean 2020-04-29

配置代碼

@Bean public ShiroFilterFactoryBean (@Qualifier("securityManager") SecurityManager securityManager) { log.info("進入shiroFilter"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); // 攔截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); filterChainDefinitionMap.put("/static/**", "anon"); filterChainDefinitionMap.put("/user/login", "anon"); filterChainDefinitionMap.put("/user/logout", "logout"); // 根據用戶的角色賦予相應的權限 // filterChainDefinitionMap.put("/add", "roles[admin]"); // filterChainDefinitionMap.put("/delete", "roles[admin]"); // filterChainDefinitionMap.put("/delete", "roles[author]");
        filterChainDefinitionMap.put("/addPermission", "roles[author]"); filterChainDefinitionMap.put("/add", "perms[user:add]"); filterChainDefinitionMap.put("/delete", "perms[user:delete]"); filterChainDefinitionMap.put("/userList", "perms[user:list]"); // 匹配所有的路徑 // 通過Map集合組成了一個攔截器鏈 ,自頂向下過濾,一旦匹配,則不再執行下面的過濾 // 如果下面的定義與上面沖突,那按照了誰先定義誰說了算 // 一定要配置在最后
        filterChainDefinitionMap.put("/**", "authc"); // 將攔截器鏈設置到shiro中
 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); // 如果不設置默認會自動尋找Web工程根目錄下的"/login.html"頁面
        shiroFilterFactoryBean.setLoginUrl("/login"); // 登錄成功后要跳轉的鏈接
        shiroFilterFactoryBean.setSuccessUrl("/index"); // 未授權頁面
        shiroFilterFactoryBean.setUnauthorizedUrl("/403"); return shiroFilterFactoryBean; }

 

繼承鏈

ShiroFilterFactoryBean實現了FactoryBean和BeanPostProcessor接口

 

1、BeanPostProcessor接口的實現

/** * Inspects a bean, and if it implements the {@link Filter} interface, automatically adds that filter * instance to the internal {@link #setFilters(java.util.Map) filters map} that will be referenced * later during filter chain construction. */
// 檢查一個bean,如果它實現了filter接口,自動將該過濾器添加到內部filters map中,稍后在過濾器鏈的構建過程中再引用該實例(后面第4點createFilterChainManager )
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof Filter) { log.debug("Found filter chain candidate filter '{}'", beanName); Filter filter = (Filter) bean; // 應用全局配置
 applyGlobalPropertiesIfNecessary(filter); // 將在Spring中注冊(而不是在ShiroFilterFactoryBean中配置的)的Filter並入. // 這里面就牽扯出一個有趣的問題 : FactoryBean<T>接口的getObject方法和 BeanPostProcessor接口的postProcessBeforeInitialization的執行先后順序? // (為了保證不遺漏Filter, 我們可以猜測后者必須優先於前者。) // 上面這個括號里面的參考下面博客的說法有一點要注意的是,打斷點調試確實是postProcessBeforeInitialization先進去的但是並沒有進去找到任何的filter,因為我是注解提供的filterMap,所以是在執行createFilterChainManager的時候先查找default的filter再添加我們在config類中傳進去的flterMap解析filter到filterChainManager中。我猜測如果是有xml配置的話,應該是postProcessBeforeInitialization最先讀取xml配置中的filter的 // 這里先記錄一下吧
 getFilters().put(beanName, filter); } else { log.trace("Ignoring non-Filter bean '{}'", beanName); } return bean; }

 

2、FactoryBean的接口實現

FactoryBean說白了就是一個工廠類的bean可以生產我們自己定義的bean並進行一些裝飾

可以在這里看一下BeanFactory和FactoryBean的區別https://blog.csdn.net/weixin_38361347/article/details/92852611

 public Object getObject() throws Exception { if (instance == null) { instance = createInstance(); } return instance; } public Class getObjectType() { return SpringShiroFilter.class; }

 

顯然我們的ShiroFilterFactoryBean創建的是SpringShiroFilter的實例

3、ShiroFilterFactoryBean.createInstance 方法

/** * This implementation: * <ol> * <li>Ensures the required {@link #setSecurityManager(org.apache.shiro.mgt.SecurityManager) securityManager} * property has been set</li> * <li>{@link #createFilterChainManager() Creates} a {@link FilterChainManager} instance that reflects the * configured {@link #setFilters(java.util.Map) filters} and * {@link #setFilterChainDefinitionMap(java.util.Map) filter chain definitions}</li> * <li>Wraps the FilterChainManager with a suitable * {@link org.apache.shiro.web.filter.mgt.FilterChainResolver FilterChainResolver} since the Shiro Filter * implementations do not know of {@code FilterChainManager}s</li> * <li>Sets both the {@code SecurityManager} and {@code FilterChainResolver} instances on a new Shiro Filter * instance and returns that filter instance.</li> * </ol> * * @return a new Shiro Filter reflecting any configured filters and filter chain definitions. * @throws Exception if there is a problem creating the AbstractShiroFilter instance. */
    protected AbstractShiroFilter createInstance() throws Exception { ​ log.debug("Creating Shiro Filter instance."); ​ SecurityManager securityManager = getSecurityManager(); // 創建實例之前必須設置securityManager
        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); } //看下面分析4
        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
        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: //構造SpringShiroFilter實例,由Spring管理
        return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver); }

 

翻譯一下上面的注釋

實現創建這個實例之前:

1、必須確保SecurityManager屬性已經設置了

2、創建一個FilterChainManager實例,該實例反映了我們配置的相關過濾內容filterChainDefinitionMap

3、用合適的方法包裝FilterChainManager

4、因為shiro filter 實例不能感知到FilterChainManager,我們需要給它配置解析器FilterChainResolver

5、一個新的Shiro過濾器,它反映了所有已配置的過濾器和過濾器鏈定義。

4、ShiroFilterFactoryBean.createFilterChainManager 方法

看看PathMatchingFilterChainResolver和FilterChainManager的創建過程:

protected FilterChainManager createFilterChainManager() {
        // 這個構造函數中會將shiro默認的Filter添加到FilterChainManager中.
        // 點進去查看shiro的默認filter有哪些,見后面分析5
        DefaultFilterChainManager manager = new DefaultFilterChainManager();
        Map<String, Filter> defaultFilters = manager.getFilters();
        // 將ShiroFilterFactoryBean配置的一些公共屬性(上面配置的loginUrl, successUrl,  unauthorizeUrl)應用到默認注冊的filter上去
        for (Filter filter : defaultFilters.values()) {
            applyGlobalPropertiesIfNecessary(filter);
        }
        //Apply the acquired and/or configured filters:
        // 然后再將用戶配置的Filter並入; 所以如果用戶配置了與上面同名的Filter, 則會進行覆蓋操作
        // 此處的getFilters();獲取的是當前實例的filters屬性,這個是屬性值在創建默認的DefaultFilterChainManager的時候add進去的默認filter,以及在web.xml中自定義的filter(由postProcessBeforeInitialization注入)
        Map<String, Filter> filters = getFilters();
        if (!CollectionUtils.isEmpty(filters)) {
            for (Map.Entry<String, Filter> 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:
                // spring會處理初始化問題, 所以shiro就不負責初始化了
                manager.addFilter(name, filter, false);
            }
        }
        //build up the chains:
        // 這里將處理用戶配置的ShiroFilterFactoryBean.filterChainDefinitions屬性
        Map<String, String> chains = getFilterChainDefinitionMap();
        if (!CollectionUtils.isEmpty(chains)) {
            for (Map.Entry<String, String> entry : chains.entrySet()) {
                String url = entry.getKey();
                String chainDefinition = entry.getValue();
                // 見下面分析7
                manager.createChain(url, chainDefinition);
            }
        }
        return manager;
    }

 

5、shiro的DefaultFilterChainManager()

有必要來看看DefaultFilterChainManager的源碼,分析一下上面調用到的方法。先來看看他的幾個重要的屬性:

其中filterConfig僅在初始化Filter時有效,而我們自定義的Filter都不是init的,所以該屬性可以暫時忽略()。 而后面兩張map就重要了:filters中緩存了所有添加的filter,filterChains則緩存了所有的filterChain。其中前者的key是filter name,value是Filter。而后者的key是chain name,value是NamedFilterList。 有的童鞋可能會問NamedFilterList是怎么樣的結構呢,你可以把它當成List<Filter>,這樣就好理解了

  
 private FilterConfig filterConfig;
 private Map<String, Filter> filters; //pool of filters available for creating chains
 private Map<String, NamedFilterList> filterChains; //key: chain name, value: chain
DefaultFilterChainManager manager = new DefaultFilterChainManager();
// DefaultFilterChainManager構造函數
public DefaultFilterChainManager() {
        this.addDefaultFilters(false);
    }
​
protected void addDefaultFilters(boolean init) {
        // shiro的DefaultFilter是一個枚舉類,包含下面的11種啟動時默認加載的filter
        DefaultFilter[] var2 = DefaultFilter.values();
        int var3 = var2.length;
        // 遍歷
        for(int var4 = 0; var4 < var3; ++var4) {
          DefaultFilter defaultFilter = var2[var4];
          // 把filter添加到manager中,不需要初始化,由Spring來完成
          this.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);
}

 

6、filterChainDefinitionMap

在分析createChain前先 shiro是如何處理上面spring-shiro.xml中用戶配置的 ShiroFilterFactoryBean.filterChainDefinitions屬性的

下面的是使用xml配置時shiro讀取配置文件的實現

//---------- ShiroFilterFactoryBean.setFilterChainDefinitions方法
public void setFilterChainDefinitions(String definitions) {
    // 使用Ini類來解析用戶配置的信息
    Ini ini = new Ini();
    ini.load(definitions);
    //did they explicitly state a 'urls' section?  Not necessary, but just in case:
    Ini.Section section = ini.getSection(IniFilterChainResolverFactory.URLS);
    if (CollectionUtils.isEmpty(section)) {
        //no urls section.  Since this _is_ a urls chain definition property, just assume the
        //default section contains only the definitions:
        section = ini.getSection(Ini.DEFAULT_SECTION_NAME);
    }
    // 將解析出來的結果賦值給ShiroFilterFactoryBean的filterChainDefinitionMap字段
    setFilterChainDefinitionMap(section);
}

 


還有另外一種方式,在代碼中使用注解的配置方式,直接用代碼給filterChainDefinitionMap賦值即可,即本文最開頭的配置代碼中的方式

  // 將攔截器鏈設置到shiro中
 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

7、DefaultFilterChainManager.createChain方法

這個方法執行完之后,用戶配置的url權限校驗(即ShiroFilterFactoryBean的filterChainDefinitions參數)就算是解析到位了(存放到了DefaultFilterChainManager的filterChains參數中)。

public void createChain(String chainName, String chainDefinition) {
        // 以上面配置的filterChainDefinitions參數舉例:    
        // 參數chainName形如 /admin/list**
        // 參數chainDefinition形如 authc,perms[admin:manage]
        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]" }
        //以上我們就可以看出我們所配置的ShiroFilterFactoryBean的filterChainDefinitions里的 每一行 會在這里被完整解析
        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) {
            /* toNameConfigPair的解析結果參見下面這個,摘選自官方
        Input               Result 
        
        foo                 returned[0] == foo
                            returned[1] == null 
                            
        foo[bar, baz]       returned[0] == foo
                            returned[1] == bar, baz 
        */
            String[] nameConfigPair = toNameConfigPair(token);
            //now we have the filter name, path and (possibly null) path-specific config.  Let's apply them:
            // 見分析8
            addToChain(chainName, nameConfigPair[0], nameConfigPair[1]);
        }
    }

 

8、DefaultFilterChainManager.addToChain方法

public void addToChain(String chainName, String filterName, String chainSpecificFilterConfig) {
        if (!StringUtils.hasText(chainName)) {
            throw new IllegalArgumentException("chainName cannot be null or empty.");
        }
        // 如果用戶沒有配置該filter, 則直接拋出的異常
        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).");
        }
        // 保存用戶配置的url與filter之間的映射關系,注冊到filter中
        applyChainConfig(chainName, filter, chainSpecificFilterConfig);
        // chainName為配置的url路徑
        // 這里會以用戶配置的url路徑來創建一個SimpleNamedFilterList示例;  並添加到DefaultFilterChainManager內部的Map<String, NamedFilterList>類型的類級字段filterChains中(以用戶配置的url路徑為key——即filterChainDefinitions參數里每一行等號左邊的部分)
        NamedFilterList chain = ensureChain(chainName);
        chain.add(filter);
    }

 

說明

前面八小節主要分析了shiroFilterFactoryBean創建一個實例的流程,主要包含創建FilterChainManager,filter的

裝載到鏈的過程,后面部分主要是講filter生效的過程源碼。

 

至此,FilterChainManager就創建完了,它無非就是緩存了兩張map,沒有什么邏輯上的操作。下面將FilterChainManager設置到PathMatchingFilterChainResolver中。PathMatchingFilterChainResolver實現了FilterChainResolver接口,該接口中只定義了一個方法:

FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain);

通過解析請求來得到一個新的FilterChain。而PathMatchingFilterChainResolver實現了該接口,依靠了FilterChainManager中保存的chainFilters和filters這兩張map來根據請求路徑解析出相應的filterChain,並且和originalChain組合起來使用。下面具體看看PathMatchingFilterChainResolver中的實現:

  
 public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        // 得到 FilterChainManager 
        FilterChainManager filterChainManager = getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        }
​
        String requestURI = getPathWithinApplication(request);
​
        // chainNames就是剛定義的filterChains的keySet,也就是所有的路徑集合(比如:["/resources/**","/login"])
        for (String pathPattern : filterChainManager.getChainNames()) {
​
            // 請求路徑是否匹配某個 定義好的路徑:
            if (pathMatches(pathPattern, requestURI)) {
                if (log.isTraceEnabled()) {
                    log.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + requestURI + "].  " + "Utilizing corresponding filter chain...");
                }
                // 找到第一個匹配的Filter鏈,那么就返回一個ProxiedFilterChain
                return filterChainManager.proxy(originalChain, pathPattern);
            }
        }
​
        return null;
    }

 

這里返回只有兩種情況,要么是null,要么就是一個ProxiedFilterChain。返回null並不表示中斷FilterChain,而是只用originChain。而關於ProxiedFilterChain,它實現了FilterChain,內部維護了兩份FilterChain(其實一個是FilterChain,另一個是List<Filter> FilterChain也就是web.xml中注冊的Filter形成的FilterChain,我們稱之為originChain。而另一個List<Filter>則是我們在Shiro中注冊的Filter鏈了,下面看看ProxiedFilterChain中關於doFilter(...)的實現:

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        if (this.filters == null || this.filters.size() == this.index) {
            //we've reached the end of the wrapped chain, so invoke the original one:
            if (log.isTraceEnabled()) {
                log.trace("Invoking original filter chain.");
            }
            this.orig.doFilter(request, response);
        } else {
            if (log.isTraceEnabled()) {
                log.trace("Invoking wrapped filter at index [" + this.index + "]");
            }
            this.filters.get(this.index++).doFilter(request, response, this);
        }
    }

 

可以看到,它會先執行Shiro中執行的filter,然后再執行web.xml中的Filter。不過要注意的是,需要等到originChain執行到ShiroFilter之后才會執行Shiro中的Filter鏈。 至此,兩個組件的創建過程差不多都介紹完了,那么當這兩個組件創建完畢后,是如何工作的呢? 先從ShiroFilter入手,因為它是總的攔截器,看看其中的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 {
                    // 其實需要關心的就在這里
                    // touch一下session
                    updateSessionLastAccessTime(request, response);
                    // 執行Filter鏈
                    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);
        }
    }
跟進executeChain(...)方法:

    protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain)
            throws IOException, ServletException {
        FilterChain chain = getExecutionChain(request, response, origChain);
        chain.doFilter(request, response);
    }

 

如何得到FilterChain的呢?如果你認真的看到這里,那么你應該不難想到其中肯定利用了剛才注冊的ChainResolver:

  
 protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
        FilterChain chain = origChain;
​
        FilterChainResolver resolver = getFilterChainResolver();
        if (resolver == null) {
            log.debug("No FilterChainResolver configured.  Returning original FilterChain.");
            return origChain;
        }
​
        FilterChain resolved = resolver.getChain(request, response, origChain);
        if (resolved != null) {
            log.trace("Resolved a configured FilterChain for the current request.");
            chain = resolved;
        } else {
            log.trace("No FilterChain configured for the current request.  Using the default.");
        }
​
        return chain;
    }

 

猜對了~並且也驗證了當resolver.getChain(...)返回null時,直接使用originChain了。然后執行返回的FilterChain的doFilter(...)方法。這個過程我們再脫離代碼來分析一下:當我們從瀏覽器發出一個請求,究竟發生了什么? 這里只站在Filter的層面來分析。服務器啟動后,讀取web.xml中的filter、filter-mapping節點后組成FilterChain,對請求進行攔截。攔截的順序按照filter節點的定義順序,Shiro利用ShiroFilter來充當一個總的攔截器來分發所有需要被Shiro攔截的請求,所以我們看到在Shiro中我們還可以自定義攔截器。ShiroFilter根據它在攔截器中的位置,只要執行到了那么就會暫時中斷原FilterChain的執行,先執行Shiro中定義的Filter,最后再執行原FilterChian。可以打個比方,比如說本來有一條鐵鏈,一直螞蟻從鐵鏈的開端往末端爬,其中某一環叫ShiroFilter,那么當螞蟻爬到ShiroFilter這一環時,將鐵鏈打斷,並且接上另一端鐵鏈(Shiro中自定義的Filter),這樣就構成了一條新的鐵鏈。然后螞蟻繼續爬行(后續的執行過程)。

到這里,我們已經根據請求路徑找到了一條Filter鏈(originChain + shiroChain),之后就是對鏈上的Filter做doFilter,其中關於如何 就是filter后配置的[]部分是如何生效的,我們可以看PathMatchingFilter中的Prehandle(...)方法:

    
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
​
        if (this.appliedPaths == null || this.appliedPaths.isEmpty()) {
            if (log.isTraceEnabled()) {
                log.trace("appliedPaths property is null or empty.  This Filter will passthrough immediately.");
            }
            return true;
        }
​
        // appliedPaths中保存了該filter中能攔截的路徑和該路徑配置的key-value對,比如{key="/admin/**", value="[admin]"}
        for (String path : this.appliedPaths.keySet()) {
            // 首先是匹配路徑
            if (pathsMatch(path, request)) {
                log.trace("Current requestURI matches pattern '{}'.  Determining filter chain execution...", path);
                // 然后開始驗證“[]”中的字符串
                Object config = this.appliedPaths.get(path);
                return isFilterChainContinued(request, response, path, config);
            }
        }
​
        //no path matched, allow the request to go through:
        return true;
    }

 

下面跟蹤isFilterChainContinued(...):

private boolean isFilterChainContinued(ServletRequest request, ServletResponse response,
                                           String path, Object pathConfig) throws Exception {
​
        if (isEnabled(request, response, path, pathConfig)) { //isEnabled check added in 1.2
            if (log.isTraceEnabled()) {
                 // log
            }
            return onPreHandle(request, response, pathConfig);
        }
​
        if (log.isTraceEnabled()) {
            // log
        }
        return true;
    }

 

基本也就是交給onPreHandle(...)來處理,所以一般需要驗證”[]“中字符串的filter都會擴展這個方法,比如AccessControlFilter:

  
 public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        return isAccessAllowed(request, response, mappedValue) || onAccessDenied(request, response, mappedValue);
    }

// 而RolesAuthorizationFilter中:
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { ​ Subject subject = getSubject(request, response); String[] rolesArray = (String[]) mappedValue; ​ if (rolesArray == null || rolesArray.length == 0) { //no roles specified, so nothing to check - allow access. return true; } ​ Set<String> roles = CollectionUtils.asSet(rolesArray); return subject.hasAllRoles(roles); }

 

細節

這里面就牽扯出一個有趣的問題 : FactoryBean<T>接口的getObject方法和 BeanPostProcessor接口的postProcessBeforeInitialization的執行先后順序?

為了保證不遺漏Filter,我們可以猜測后者必須優先於前者。因為創建實例要讀取初始化的默認filter

上面這個說法參考下面第一個博客的說法有一點要注意的是,打斷點調試確實是postProcessBeforeInitialization先進去的但是並沒有進去找到任何的filter,因為我是注解提供的filterMap,所以是在執行createFilterChainManager的時候先查找default的filter再添加我們在config類中傳進去的flterMap解析filter到filterChainManager中。我猜測如果是有xml配置的話,應該是postProcessBeforeInitialization最先讀取xml配置中的filter的,但是如果是xml配置應該是一開始在postProcessBeforeInitialization中是找不到的

總結

在兩位大佬的基礎上進行了理解,代碼的一步步跟蹤,分析源代碼的時候結合ide的debug功能打斷點一行行的跳轉,加深理解,再加上自己的注釋,后面那位花了兩天時間走完了,我也差不多,哈哈哈哈哈。。做個筆記,防止忘記。

參考

參考文章:https://blog.csdn.net/lqzkcx3/article/details/78776555

               https://blog.csdn.net/u012345283/article/details/44199791

![1588042373222](C:\Users\Henry Hu.DESKTOP-C8EDL2H\AppData\Roaming\Typora\typora-user-images\1588042373222.png)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM