1. 程式人生 > >CAS源碼追蹤系列一:Filter的初始化

CAS源碼追蹤系列一:Filter的初始化

引入 委托 ppi 假設 文檔 client 通過 tomcat容器 發現

目錄

  • 代碼跟蹤
    • Spring-web:DelegatingFilterProxy
    • CAS:AuthenticationFilter
  • 總結

最近研究了一下SSO(Single Sign On:單點登錄)原理。
於是想借助CAS(基於SSO原理的實現框架)加深一下理解同時參考一下具體代碼實現,因此有了此系列文章。
先從CAS-CLIENT說起。

假設你已經掌握了如何在你的web項目中引入CAS。我們以AuthenticationFilter為例,說一說它是如何從初始化的。

代碼跟蹤

Spring-web:DelegatingFilterProxy

在web項目中的web.xml文件中我們通常通過如下方式進行spring和cas的整合:

<bean id="authenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter">
  <property name="casServlerLoginUrl">xxx</property>
  <property name="serverName">xxx</property>
</bean>
<filter>
  <filter-name>casAuthenticationFilter</filter-name>
  <filter-class>
  org.springframework.web.filter.DelegatingFilterProxy
  </filter-class>
  <init-param>
    <param-name>targetBeanName</param-name>
    <param-value>authenticationFilter</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>casAuthenticationFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

可以看到引入了一個名為DelegatingFilterProxy的Filter。那我們來看一下該類的源碼:

public class DelegatingFilterProxy extends GenericFilterBean {
    private String contextAttribute;//上下文屬性,尋找WebApplicationContext
    private WebApplicationContext webApplicationContext;//web上下文
    private String targetBeanName;//被委托的Filter的名字,如果沒有指定,則使用DelegatingFilterProxy對應的Filter的name,即上面的<filter-name>標簽的內容。
    private boolean targetFilterLifecycle;//是否是目標Filter的生命周期,默認為false,即由Spring來管理Filter的生命周期,否則由Servlet來管理。
    private Filter delegate;//被委托的過濾器
    private final Object delegateMonitor;//監視器
    ...

該類是實現了Filter接口並交由spring管理的servlet過濾器的代理類。
因為這個類也是實現了Filter接口,所以在tomcat容器初始化是會執行init(FilterConfig)方法。該方法來自其父類GenericFilterBean,來看代碼:

public final void init(FilterConfig filterConfig) throws ServletException {
        ...
        this.filterConfig = filterConfig;
        ...
        this.initFilterBean();
    }

註意到this.initFilterBean(),該方法來自DelegatingFilterProxy,看源碼:

protected void initFilterBean() throws ServletException {
                ...
                WebApplicationContext wac = this.findWebApplicationContext();//獲取應用上下文
                if (wac != null) {
                    this.delegate = this.initDelegate(wac);//初始化委托
               ...
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
        Filter delegate = (Filter)wac.getBean(this.getTargetBeanName(), Filter.class);//從應用上下文中獲取名為targetBeanName的bean,也就是被委托的Filter
        if (this.isTargetFilterLifecycle()) {
            delegate.init(this.getFilterConfig());//調用Filter的初始化方法
        }

        return delegate;
    }

CAS:AuthenticationFilter

AuthenticationFilter繼承了AbstractCasFilter。

上面說到調用Filter自己的初始化方法。對於AuthenticationFilter,因為自己沒有重寫init(FilterConfig),則會調用從其父類AbstractCasFilter繼承來的init(FilterConfig)方法:

public final void init(FilterConfig filterConfig) throws ServletException {
        if (!this.isIgnoreInitConfiguration()) {
            ...
            this.initInternal(filterConfig);//內部初始化
        }

        this.init();//自定義初始化邏輯
    }

註意:你會發現AuthenticationFilter和其父類都有initInternal(filterConfig)和init()方法,這裏進入的是AuthenticationFilter,所以回去調用AuthenticationFilter中對應的方法:

protected void initInternal(FilterConfig filterConfig) throws ServletException {//將filterConfig設置到WebXmlConfigurationStrategyImpl以及設置一些自己的屬性值
            ...
            super.initInternal(filterConfig);//此時才去調用其父類的initInternal(filterConfig)
            ...
    }

public void init() {
        super.init();//此時才去調用其父類的init()
        ...
    }

直觀的圖示(非專業,手動滑稽~):
技術分享圖片

總結

本文從web項目和spring的整合入手,以cas中的AuthenticationFilter為例(其他類型的Filter類似)跟蹤代碼分析如何走到他自己的初始化邏輯。後續會有初始化之後對請求的攔截、cas服務端的處理等分析。

碼字整理不易,如何你覺得寫的還能看的話請賞一個贊或者推薦吧,如果寫的不對請直接評論糾正,畢竟我還是一個在路上的小魯班呢~

歡迎關註我的公眾號,不定期更新學習筆記和視頻文檔學習資料哦~
技術分享圖片

CAS源碼追蹤系列一:Filter的初始化