單點登入,session超時, ajax連結處理
1 錯誤場景
部署問題:用nginx封裝,service攜帶不過來。
2 cas 針對session超時設定
cas對於session超時設定,可以設定檔案cas\WEB-INF\spring-configuration\ticketExpirationPolicies.xml 進行設定,如下所示:
[html] view plain copy print?- <beanid=“grantingTicketExpirationPolicy”class=“org.jasig.cas.ticket.support.RememberMeDelegatingExpirationPolicy”
- <propertyname=“sessionExpirationPolicy”>
- <beanclass=“org.jasig.cas.ticket.support.TimeoutExpirationPolicy”>
- <constructor-argindex=“0”value=“20000”/>
- </bean>
- </property>
[html] view plain copy print?<bean id="grantingTicketExpirationPolicy" class="org.jasig.cas.ticket.support.RememberMeDelegatingExpirationPolicy"> <property name="sessionExpirationPolicy"> <bean class="org.jasig.cas.ticket.support.TimeoutExpirationPolicy"> <constructor-arg index="0" value="20000" /> </bean> </property>
- <beanid=“serviceTicketExpirationPolicy”class=“org.jasig.cas.ticket.support.MultiTimeUseOrTimeoutExpirationPolicy”>
- <!– This argument is the number of times that a ticket can be used before its considered expired. –>
- <constructor-arg
- index=“0”
- value
- <!– This argument is the time a ticket can exist before its considered expired. –>
- <constructor-arg
- index=“1”
- value=“20000”/>
- </bean>
<bean id="serviceTicketExpirationPolicy" class="org.jasig.cas.ticket.support.MultiTimeUseOrTimeoutExpirationPolicy">
<!-- This argument is the number of times that a ticket can be used before its considered expired. -->
<constructor-arg
index="0"
value="1" />
<!-- This argument is the time a ticket can exist before its considered expired. -->
<constructor-arg
index="1"
value="20000" />
</bean>
上述兩個bean中,設定為20000毫秒(設定超時單位為毫秒),上述另個bean的機制就如同session機制一樣,當用戶沒有與伺服器的互動超過20秒,點選url,便會自動轉到登入介面。單只是設定這一點是不夠的,會有問題的。
問題:當你的專案中也有對session的設定,以及對session時間的設定的時候,只設置cas的session超時是不管事的。
3 配置完畢,對於ajax請求出現的錯誤
問題的解決:所以我們需要把專案中session超時的時間和cas session超時的時間設定為一致,因為cas對session超時的處理,是在cas-client-core-3.2.1.jar 包中,而cas的客戶端是和專案放在一起的,所以對session處理機制是一樣的。
當然上述的處理一般情況下是沒有問題的,但當遇到ajax請求,就不可以了,會報如下錯誤:
千萬別被Origin矇蔽,開始定位錯誤定位在跨域問題,因為網上查詢說也是跨域問題,而實際上對於非ajax請求,cas攔截處理後是可以跳轉到登入頁面的,這說明了是可以請求給cas的,只不過cas對ajax的請求無法做出session失效的處理,這怎麼辦呢?只能去改CAS原始碼了。不知道是cas矮,還是自己太矮了。。。
4 修改CAS原始碼,解決上述問題
經過檢視錯誤日誌,找到cas列印日誌的地方,找到cas處理session的方法,修改的是/CAS_Client/src/org/jasig/cas/client/authentication/AuthenticationFilter.Java這個java類。修改的doFilter方法如下所示。
[java] view plain copy print?- publicfinalvoid doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
- final HttpServletRequest request = (HttpServletRequest) servletRequest;
- final HttpServletResponse response = (HttpServletResponse) servletResponse;
- final HttpSession session = request.getSession(false);
- final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
- if (assertion != null) {
- filterChain.doFilter(request, response);
- return;
- }
- final String serviceUrl = constructServiceUrl(request, response);
- final String ticket = CommonUtils.safeGetParameter(request,getArtifactParameterName());
- finalboolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
- if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
- filterChain.doFilter(request, response);
- return;
- }
- final String modifiedServiceUrl;
- log.debug(”no ticket and no assertion found”);
- if (this.gateway) {
- log.debug(”setting gateway attribute in session”);
- modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
- } else {
- modifiedServiceUrl = serviceUrl;
- }
- if (log.isDebugEnabled()) {
- log.debug(”Constructed service url: ” + modifiedServiceUrl);
- }
- final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
- if (log.isDebugEnabled()) {
- log.debug(”redirecting to \”“ + urlToRedirectTo + “\”“);
- }
- log.debug(”判斷拼接的過程,引數, 最終拼接好的地址為: \”“ + urlToRedirectTo + “\”“);
- //response.sendRedirect(urlToRedirectTo);
- String url = request.getRequestURL().toString();
- log.debug(”url——request.getRequestURL().toString()=———:” + url);
- String contextPath = request.getContextPath();
- log.debug(”contextPath ———request.getContextPath()=——-:” + contextPath);
- url = url.substring(0, (url.indexOf(contextPath)+contextPath.length()));
- log.debug(”url = ——session消失,擷取到專案的url—” + url);
- String urls = urlToRedirectTo;
- //判斷是否是第一次轉到.
- if(“”.equals(url)||url==null||url.length()==0){
- log.debug(”url–第一次為空,不擷取—–” + url);
- urls = urlToRedirectTo;
- //response.sendRedirect(urlToRedirectTo);
- }else{
- urls = urls.substring(0, (urls.indexOf(“service=”)+8)) + URLEncoder.encode(url,“UTF-8”);
- }
- log.debug(”urls –最終輸入到瀏覽器的地址是———–” + urls);
- response.setContentType(”text/html;charset=UTF-8”);
- response.getWriter().write(”<script languge=’javascript’>window.location.href=’”+urls+“/’</script>”);
- }
public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final HttpSession session = request.getSession(false);
final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;
if (assertion != null) {
filterChain.doFilter(request, response);
return;
}
final String serviceUrl = constructServiceUrl(request, response);
final String ticket = CommonUtils.safeGetParameter(request,getArtifactParameterName());
final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
filterChain.doFilter(request, response);
return;
}
final String modifiedServiceUrl;
log.debug("no ticket and no assertion found");
if (this.gateway) {
log.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
if (log.isDebugEnabled()) {
log.debug("Constructed service url: " + modifiedServiceUrl);
}
final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
if (log.isDebugEnabled()) {
log.debug("redirecting to \"" + urlToRedirectTo + "\"");
}
log.debug("判斷拼接的過程,引數, 最終拼接好的地址為: \"" + urlToRedirectTo + "\"");
//response.sendRedirect(urlToRedirectTo);
String url = request.getRequestURL().toString();
log.debug("url------request.getRequestURL().toString()=---------:" + url);
String contextPath = request.getContextPath();
log.debug("contextPath ---------request.getContextPath()=-------:" + contextPath);
url = url.substring(0, (url.indexOf(contextPath)+contextPath.length()));
log.debug("url = ------session消失,擷取到專案的url---" + url);
String urls = urlToRedirectTo;
//判斷是否是第一次轉到.
if("".equals(url)||url==null||url.length()==0){
log.debug("url--第一次為空,不擷取-----" + url);
urls = urlToRedirectTo;
//response.sendRedirect(urlToRedirectTo);
}else{
urls = urls.substring(0, (urls.indexOf("service=")+8)) + URLEncoder.encode(url,"UTF-8");
}
log.debug("urls --最終輸入到瀏覽器的地址是-----------" + urls);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("<script languge='javascript'>window.location.href='"+urls+"/'</script>");
}
這樣不但解決了cas對ajax地址處理,並且解決了另一個問題,因為最初的改動不是上述的程式碼,中間出現了一個小插曲,部署的時候出現的bug,登入時service引數攜帶不過來。當我們把專案部署到Linux上時,用nginx代理,並配置tomcat的sever.xml檔案封裝專案名稱, 則樣,域名“封裝”了ip+埠號+專案名稱,使用者不需要再輸入專案名稱了。所以程式碼中對使用者第一次登入做判斷,判斷是否是第一次登入還是session失效呼叫的這個方法,這樣就解決了nginx代理出現的問題了。
5 總結
錯誤未出現時:黑暗前的黎明
錯誤出現時:電閃雷鳴
錯誤解決中:時間就像過火車
錯誤解決完畢:原來神馬都是浮雲啊
方法上:這個過程就像是你回到家發現鑰匙丟在路上了,找到開門的鑰匙,要一步一個腳印的去找,對了一步再進行下一步,到底是哪一步找到了鑰匙?到底是哪一步,找到了錯誤?要相信,你永遠被錯誤幹不掉,只是你又幹掉了錯誤。是一次又一次的錯誤在改變你,而錯誤永遠變不了,就像倉央嘉措的那首情詩,《見或不見》.
bug對我的感情上:你見,或者不見我;我就在那裡;不悲不喜;你念,或者不念我;情就在那裡;不來不去;你愛,或者不愛我;愛就在那裡;不增不減;你跟,或者不跟我;我的手就在你的手裡;不捨不棄;來我的懷裡;或者讓我住進你的心裡;默然,相愛;寂靜,歡喜;