有时候各个应用希望有独立风格的登录页面,而不是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 οnlοad="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跳过测试。
修改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