有时候各个应用希望有独立风格的登录页面,而不是cas提供的统一登录页面,网上现在有几种方式:iframe, javascript。本文参考了https://wiki.jasig.org/display/CAS/Using+CAS+without+the+Login+Screen, 并在其基础上实现了登录出错重定向至自定义登录页面。
由于cas登录首先要获取lt与execution这两个参数,因此,主要实现方案就是通过在自定义登录页面加入标志位,提交到cas的登录页面casLoginView.jsp,这个页面会根据标志位进行二次提交。如果用户名密码失败还要求能够返回到原登录页面并给出提示,主要实现方式是改变cas的web flow,在提交的时候判断是否是自定义页面登录,是的话进入一个新的状态,这个状态完成页面跳转,并回传错误信息。
自定义登录页面:
<html> <head> </head> <body> <script type="text/javascript"> function getQueryStringByName(name) { var result = location.search.match(new RegExp("[\?\&]" + name+ "=([^\&]+)","i")); if(result == null || result.length < 1){ return ""; } return result[1]; } var info = getQueryStringByName('info'); if (info == "error") alert("用户名密码错误!"); </script> <form method="GET" action="http://127.0.0.1:8080/cas/login"> <p>Username : <input type="text" name="username" /></p> <p>Password : <input type="password" name="password" /></p> <p>Remember me : <input type="checkbox" name="rememberMe" value="true" /></p> <p><input type="submit" value="Login !" /></p> <input type="hidden" name="auto" value="true" /> <input type="hidden" name="login_from" value="http://127.0.0.1:8080/myApp/login.html" /> <input type="hidden" name="service" value="http://127.0.0.1:8080/myApp/users.htm" /> </form> </body> </html>
改造的cas-server-webapp工程中的cas登录页:WEB-INF/view/jsp/default/ui/casLoginView.jsp。
<%@ page contentType="text/html; charset=UTF-8" %> <% String auto = request.getParameter("auto"); if (auto != null && auto.equals("true")) { %> <html> <head> <script language="javascript"> function doAutoLogin() { document.forms[0].submit(); } </script> </head> <body onload="doAutoLogin();"> <form id="credentials" method="POST" action="<%= request.getContextPath() %>/login?service=<%= request.getParameter("service") %>"> <input type="hidden" name="lt" value="${loginTicket}" /> <input type="hidden" name="execution" value="${flowExecutionKey}" /> <input type="hidden" name="_eventId" value="submit" /> <input type="hidden" name="username" value="<%= request.getParameter("username") %>" /> <input type="hidden" name="password" value="<%= request.getParameter("password") %>" /> <input type="hidden" name="login_from" value="<%= request.getParameter("login_from") %>" /> <% if ("true".equals(request.getParameter("rememberMe"))) {%> <input type="hidden" name="rememberMe" value="true" /> <% } %> <input type="submit" value="Submit" style="visibility: hidden;" /> </form> </body> </html> <% } else { %> <jsp:directive.include file="includes/top.jsp" /> ...... <jsp:directive.include file="includes/bottom.jsp" /> <% } %>
cas-server-core工程的AuthenticationViaFormAction.java需要改造:
在submit函数中,改造如下:
try { WebUtils.putTicketGrantingTicketInRequestScope(context, this.centralAuthenticationService.createTicketGrantingTicket(credentials)); putWarnCookieIfRequestParameterPresent(context); return "success"; } catch (final TicketException e) { String login_from = context.getRequestParameters().get("login_from"); if (login_from != null && login_from.length() > 0) { context.getRequestScope().put("redirectUrl", login_from + "?info=error"); return "customizedRedirect"; } populateErrorsInstance(e, messageContext); if (isCauseAuthenticationException(e)) { return getAuthenticationExceptionEventId(e); } return "error"; }
其中
String login_from = context.getRequestParameters().get("login_from"); if (login_from != null && login_from.length() > 0) { context.getRequestScope().put("redirectUrl", login_from + "?info=error"); return "customizedRedirect"; }
是新加的。
注意,maven编译cas-server-core最好采用-Dmaven.test.skip=true clean package install跳过测试。
然后在cas-server-webapp工程中
修改WEB-INF/login-webflow.xml,
<action-state id="realSubmit"> <evaluate expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credentials, messageContext)" /> <!-- To enable LPPE on the 'warn' replace the below transition with: <transition on="warn" to="passwordPolicyCheck" /> CAS will attempt to transition to the 'warn' when there's a 'renew' parameter and there exists a ticketGrantingId and a service for the incoming request. --> <transition on="warn" to="warn" /> <!-- To enable LPPE on the 'success' replace the below transition with: <transition on="success" to="passwordPolicyCheck" /> --> <transition on="success" to="sendTicketGrantingTicket" /> <transition on="error" to="generateLoginTicket" /> <!--加入该transition , 当验证失败之后转到自定义页面 --> <transition on="customizedRedirect" to="customizedRedirectView" /> <transition on="accountDisabled" to="casAccountDisabledView" /> <transition on="mustChangePassword" to="casMustChangePassView" /> <transition on="accountLocked" to="casAccountLockedView" /> <transition on="badHours" to="casBadHoursView" /> <transition on="badWorkstation" to="casBadWorkstationView" /> <transition on="passwordExpired" to="casExpiredPassView" /> </action-state>
其中
<transition on="customizedRedirect" to="customizedRedirectView" />
是新加的。
另外,还要新加一个状态:
<end-state id="customizedRedirectView" view="externalRedirect:${requestScope.redirectUrl}" />
备注:
cas 源码下载地址http://downloads.jasig.org/cas/ 我用的是3.5.2
另外,可以直接用我已经编译好的http://download.csdn.net/detail/sundongsdu/6681187