下載cas-client,地址:http://www.ja-sig.org/downloads/cas-clients/,當前最新版本是cas-client-3.2.1-release.zip。然后解壓cas-client-3.2.1-release.zip,在modules拷貝cas-client-core-3.2.1.jar到應用的WEB-INF/lib目錄中。
除了在web.xml添加CAS內(nèi)置的filter外(具體看配置web.xml),我們需要撰寫自己支持CAS集成的客戶化包。大致思路如下:
@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; HttpSession session = request.getSession(); //在session中自定義一個參數(shù),以它來校驗是否完成過自動登陸 Object user_login = session.getAttribute(AURORA_USER_LOGIN); if (user_login != null){ //登陸過,就繼續(xù)執(zhí)行其他filter filterChain.doFilter(request, response); return; } //通過CAS的API獲得登陸賬號 String loginName = AssertionHolder.getAssertion().getPrincipal().getName(); try { //執(zhí)行本系統(tǒng)的登陸。跟平常同時校驗用戶名和密碼不同,這里只有用戶名。 executeLoginProc(request,response,loginName); } catch (Exception e) { logger.log(Level.SEVERE, "executeLoginProc error:", e); return; } //登陸成功 session.setAttribute(AURORA_USER_LOGIN, Boolean.TRUE); //跳轉到登陸成功后的頁面 response.sendRedirect(roleSelectPageUrl); }把這個class打包成一個jar拷貝到應用的WEB-INF/lib目錄中。
如果有興趣,還可以簡單了解下org.jasig.cas.client.authentication.AuthenticationFilter這個CAS內(nèi)置filter的功能
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest)servletRequest; HttpServletResponse response = (HttpServletResponse)servletResponse; HttpSession session = request.getSession(false); //檢查自定義屬性"_const_cas_assertion_" Assertion assertion = session != null ? (Assertion)session.getAttribute("_const_cas_assertion_") : null;
if (assertion != null) { //已經(jīng)成功登陸過CAS filterChain.doFilter(request, response); return; } //拿到url,并檢查url參數(shù)中的ticket是否有效 String serviceUrl = constructServiceUrl(request, response); String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName()); boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if ((CommonUtils.isNotBlank(ticket)) || (wasGatewayed)) { //ticket有效 filterChain.doFilter(request, response); return; }
this.log.debug("no ticket and no assertion found"); String modifiedServiceUrl; String modifiedServiceUrl; if (this.gateway) { this.log.debug("setting gateway attribute in session"); modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl); } else { modifiedServiceUrl = serviceUrl; }
if (this.log.isDebugEnabled()) { this.log.debug("Constructed service url: " + modifiedServiceUrl); }
String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
if (this.log.isDebugEnabled()) { this.log.debug("redirecting to \"" + urlToRedirectTo + "\""); } //重定向到cas的登陸頁面 response.sendRedirect(urlToRedirectTo); }
在應用WEB-INF/web.xml添加filter的內(nèi)容,效果如下所示
<!-- ======================== 單點登錄開始 ======================== --> <!-- 用于單點退出,該過濾器用于實現(xiàn)單點登出功能,可選配置--> <listener> <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class> </listener> <!-- 該過濾器用于實現(xiàn)單點登出功能,可選配置。 --> <filter> <filter-name>CAS Single Sign Out Filter</filter-name> <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class> </filter> <filter-mapping> <filter-name>CAS Single Sign Out Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 該過濾器負責用戶的認證工作,必須啟用它 --> <filter> <filter-name>CASFilter</filter-name> <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> <init-param> <param-name>casServerLoginUrl</param-name> <param-value>https://sso.aurora-framework.org:8080/cas/login</param-value> <!--這里的server是服務端的IP--> </init-param> <init-param> <param-name>serverName</param-name> <param-value>https://sso.aurora-framework.org:8080</param-value> </init-param> </filter> <filter-mapping> <filter-name>CASFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 該過濾器負責對Ticket的校驗工作,必須啟用它 --> <filter> <filter-name>CAS Validation Filter</filter-name> <filter-class> org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class> <init-param> <param-name>casServerUrlPrefix</param-name> <param-value>https://sso.aurora-framework.org:8080/cas</param-value> </init-param> <init-param> <param-name>serverName</param-name> <param-value>https://sso.aurora-framework.org:8080</param-value> </init-param> </filter> <filter-mapping> <filter-name>CAS Validation Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 該過濾器負責實現(xiàn)HttpServletRequest請求的包裹, 比如允許開發(fā)者通過HttpServletRequest的getRemoteUser()方法獲得SSO登錄用戶的登錄名,可選配置。 --> <filter> <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name> <filter-class> org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class> </filter> <filter-mapping> <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 該過濾器使得開發(fā)者可以通過org.jasig.cas.client.util.AssertionHolder來獲取用戶的登錄名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 --> <filter> <filter-name>CAS Assertion Thread Local Filter</filter-name> <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class> </filter> <filter-mapping> <filter-name>CAS Assertion Thread Local Filter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 自動根據(jù)單點登錄的結果設置本系統(tǒng)的用戶信息--> <filter> <display-name>AutoSetUserAdapterFilter</display-name> <filter-name>AutoSetUserAdapterFilter</filter-name> <filter-class>aurora.plugin.sso.cas.AutoSetUserFilter</filter-class> <init-param> <param-name>roleSelectPageUrl</param-name> <param-value>https://sso.aurora-framework.org:8080/yourapp/role_select.screen</param-value> </init-param> </filter> <filter-mapping> <filter-name>AutoSetUserAdapterFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- ======================== 單點登錄結束 ======================== -->
前面幾個都是CAS的標準配置,最后一個AutoSetUserAdapterFilter(自定義,可以取其他任意名字)才是我們支持cas的客戶化程序。其中roleSelectPageUrl是指用戶完成單點登錄后跳轉的頁面。
本文檔撰寫時java web項目和CAS用同一個tomcat,所以都用的https。否則只需要配置CAS的鏈接為HTTPS,本項目連接用HTTP。
CAS默認的邏輯是用戶名和密碼一致就可以登陸,現(xiàn)在需要把原web系統(tǒng)的用戶名和密碼校驗挪到CAS中。這里假設原先web系統(tǒng)中有一張sys_user表存儲了用戶名和MD5散列后的密碼。
打開cas/WEB-INF/deployerConfigContext.xml
- 注釋掉SimpleTestUsernamePasswordAuthenticationHandler這個Handler,并添加
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> <property ref="dataSource" name="dataSource"></property> <property name="sql" value="select t.encrypted_user_password from sys_user t where t.user_name=?"></property> <property ref="MD5PasswordEncoder" name="passwordEncoder"></property></bean>
在文件末尾之前加入數(shù)據(jù)庫的鏈接:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName"> <value>oracle.jdbc.driver.OracleDriver</value> </property> <property name="url"> <value>jdbc:oracle:thin:@yourIP:1521:yourOracleInstanceId</value> </property> <property name="username"> <value>yourName</value> </property> <property name="password"> <value>yourPassword</value> </property> </bean> <bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"> <constructor-arg index="0"> <value>MD5</value> </constructor-arg> </bean>
cas加入jdbc支持
復制cas-server-3.5.2\modules\cas-server-support-jdbc-3.5.2.jar和oracle驅動(這里采用oracle數(shù)據(jù))的ojdbc14.jar或者classes12.jar放到cas/WEB-INF/lib目錄下。重新登陸Web系統(tǒng)
重啟tomcat,在瀏覽器中輸入https://sso.aurora-framework.org:8080/yourapp/,自動跳轉到如下頁面:
輸入web系統(tǒng)預先定義的用戶名和密碼,并跳轉到自定義(web.xml中定義的)登陸成功后的頁面。