- 浏览: 359027 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
fengxiatao:
忘了说我邮箱了 757723745@qq.com
关于 CAS SSO 文章声明 -
fengxiatao:
请发一下最github地址给我好吗?不胜感激
关于 CAS SSO 文章声明 -
romyli:
求一个github地址.感谢分享
关于 CAS SSO 文章声明 -
zz210891470:
使用您的例子从服务器获取lt返回test-login 页面之后 ...
CAS 之自定义登录页实践 -
feiteyizu:
WANTAWAY314 写道这种方法适合移动端的单点登录不?大 ...
CAS 之自定义登录页实践
1. 动机
用过 CAS 的人都知道 CAS-Server端是单独部署的,作为一个纯粹的认证中心。在用户每次登录时,都需要进入CAS-Server的登录页填写用户名和密码登录,但是如果存在多个子应用系统时,它们可能都有相应风格的登录页面,我们希望直接在子系统中登录成功,而不是每次都要跳转到CAS的登录页去登录。
2. 开始分析问题
其实仔细想一想,为什么不能直接在子系统中将参数提交至 cas/login 进行登录呢? 于是便找到了CAS在登录认证时主要参数说明:
service [OPTIONAL] 登录成功后重定向的URL地址;
username [REQUIRED] 登录用户名;
password [REQUIRED] 登录密码;
lt [REQUIRED] 登录令牌;
主要有四个参数,其中的三个参数倒好说,最关键的就是 lt , 据官方说明该参数是login ticket id, 主要是在登录前产生的一个唯一的“登录门票”,然后提交登录后会先取得"门票",确定其有效性后才进行用户名和密码的校验,否则直接重定向至 cas/login 页。
于是,便打开CAS-Server的登录页,发现其每次刷新都会产生一个 lt, 其实就是 Spring WebFlow 中的 flowExecutionKey值。 那么问题的关键就在于在子系统中如何获取 lt 也就是登录的ticket?
3. 可能的解决方案
一般对于获取登录ticket的解决方案可能大多数人都会提到两种方法:
- AJAX: 熟悉 Ajax 的可能都知道,它的请求方式是严格按照沙箱安全模型机制的,严格情况下会存在跨域安全问题。
- IFrames: 这也是早期的 ajax 实现方式,在页面中嵌入一个隐藏的IFrame,然后通过表单提交到该iframe来实现不刷新提交,不过使用这种方式同样会带来两个问题: a. 登录成功之后如何摆脱登录后的IFrame呢?如果成功登录可能会导致整个页面重定向,当然你能在form中使
用属性target="_parent",使之弹出,那么你如何在父页面显示错误信息呢?
b. 你可能会受到布局的限止(不允许或不支持iframe)
4. 通过JS重定向来获取login ticket (lt)
当第一次进入子系统的登录页时,通过 JS 进行redirect到cas/login?get-lt=true获取login ticket,然后在该login中的 flow 中检查是否包含get-lt=true的参数,如果是的话则跳转到lt生成页,生成后,并将lt作为该redirect url 中的参数连接,如 remote-login.html?lt=e1s1,然后子系统再通过JS解析当前URL并从参数中取得该lt的值放置登录表单中,即完成 lt 的获取工作。其中进行了两次 redirect 的操作。
5. 开始实践
首先,在我们的子系统中应该有一个登录页面,通过输入用户名和密码提交至cas认证中心。不过前提是先要获取到 login tickt id. 也就是说当用户第一次进入子系统的登录页面时,在该页面中会通过js跳转到 cas/login 中的获取login ticket. 在 cas/login 的 flow 中先会判断请求的参数中是否包含了 get-lt 的参数。
在cas的 login flow 中加入 ProvideLoginTicketAction 的流,主要用于判断该请求是否是来获取 lt,在cas-server端声明获取 login ticket action 类:
com.denger.sso.web.ProvideLoginTicketAction
/** * Opens up the CAS web flow to allow external retrieval of a login ticket. * * @author denger */ public class ProvideLoginTicketAction extends AbstractAction{ @Override protected Event doExecute(RequestContext context) throws Exception { final HttpServletRequest request = WebUtils.getHttpServletRequest(context); if (request.getParameter("get-lt") != null && request.getParameter("get-lt").equalsIgnoreCase("true")) { return result("loginTicketRequested"); } return result("continue"); } } // 如果参数中包含 get-lt 参数,则返回 loginTicketRequested 执行流,并跳转至 loginTicket 生成页,否则 则跳过该flow,并按照原始login的流程来执行。
并且将该 action 声明在 cas-servlet.xml 中:
<bean id="provideLoginTicketAction" class="com.denger.sso.web.ProvideLoginTicketAction" />
还需要定义 loginTicket 的生成页也就是当返回 loginTicketRequested 的 view:
viewRedirectToRequestor.jsp
<%@ page contentType="text/html; charset=UTF-8"%> <%@ page import="com.denger.sso.util.CasUtility"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> <% String separator = ""; // 需要输入 login-at 参数,当生成lt后或登录失败后则重新跳转至 原登录页,并传入参数 lt 和 error_message String referer = request.getParameter("login-at"); referer = CasUtility.resetUrl(referer); if (referer != null && referer.length() > 0) { separator = (referer.indexOf("?") > -1) ? "&" : "?"; %> <html> <title>cas get login ticket</title> <head> <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> <script> var redirectURL = "<%=referer + separator%>lt=${flowExecutionKey}"; <spring:hasBindErrors name="credentials"> var errorMsg = '<c:forEach var="error" items="${errors.allErrors}"><spring:message code="${error.code}" text="${error.defaultMessage}" /></c:forEach>'; redirectURL += '&error_message=' + encodeURIComponent (errorMsg); </spring:hasBindErrors> window.location.href = redirectURL; </script> </head> <body></body> </html> <% } else { %> <script>window.location.href = "/member/login";</script> <% } %>
并且需要将该 jsp 声明在 default._views.properites 中:
### Redirect with login ticket view casRedirectToRequestorView.(class)=org.springframework.web.servlet.view.JstlView casRedirectToRequestorView.url=/WEB-INF/view/jsp/default/ui/viewRedirectToRequestor.jsp
相关 com.denger.sso.util.CasUtility 代码:
public class CasUtility { /** * Removes the previously attached GET parameters "lt" and "error_message" * to be able to send new ones. * * @param casUrl * @return */ public static String resetUrl(String casUrl) { String cleanedUrl; String[] paramsToBeRemoved = new String[] { "lt", "error_message", "get-lt" }; cleanedUrl = removeHttpGetParameters(casUrl, paramsToBeRemoved); return cleanedUrl; } /** * Removes selected HTTP GET parameters from a given URL * * @param casUrl * @param paramsToBeRemoved * @return */ public static String removeHttpGetParameters(String casUrl, String[] paramsToBeRemoved) { String cleanedUrl = casUrl; if (casUrl != null) { // check if there is any query string at all if (casUrl.indexOf("?") == -1) { return casUrl; } else { // determine the start and end position of the parameters to be // removed int startPosition, endPosition; boolean containsOneOfTheUnwantedParams = false; for (String paramToBeErased : paramsToBeRemoved) { startPosition = -1; endPosition = -1; if (cleanedUrl.indexOf("?" + paramToBeErased + "=") > -1) { startPosition = cleanedUrl.indexOf("?" + paramToBeErased + "=") + 1; } else if (cleanedUrl.indexOf("&" + paramToBeErased + "=") > -1) { startPosition = cleanedUrl.indexOf("&" + paramToBeErased + "=") + 1; } if (startPosition > -1) { int temp = cleanedUrl.indexOf("&", startPosition); endPosition = (temp > -1) ? temp + 1 : cleanedUrl .length(); // remove that parameter, leaving the rest untouched cleanedUrl = cleanedUrl.substring(0, startPosition) + cleanedUrl.substring(endPosition); containsOneOfTheUnwantedParams = true; } } // wenn nur noch das Fragezeichen vom query string übrig oder am // schluss ein "&", dann auch dieses entfernen if (cleanedUrl.endsWith("?") || cleanedUrl.endsWith("&")) { cleanedUrl = cleanedUrl.substring(0, cleanedUrl.length() - 1); } // parameter mehrfach angegeben wurde... if (!containsOneOfTheUnwantedParams) return casUrl; else cleanedUrl = removeHttpGetParameters(cleanedUrl, paramsToBeRemoved); } } return cleanedUrl; }
还有一处需要调整的地方就是当用户名和密码验证失败后,应该重新返回至子系统登录页,也就是 login-at 参数值,此时同样需要重新生成 login ticket。 于是找到 cas 登录验证处理 action :org.jasig.cas.web.flow.AuthenticationViaFormAction 修改 submit方法 中代码下如:
try { WebUtils.putTicketGrantingTicketInRequestScope(context, this.centralAuthenticationService.createTicketGrantingTicket(credentials)); putWarnCookieIfRequestParameterPresent(context); return "success"; } catch (final TicketException e) { populateErrorsInstance(e, messageContext); // 当验证失败后,判断参数中是否获否 login-at 参数,如果包含的话则跳转至 login ticket 获取页 String referer = context.getRequestParameters().get("login-at"); if (!org.apache.commons.lang.StringUtils.isBlank(referer)) { return "errorForRemoteRequestor"; } return "error"; }
接下来要做的就是将该action 的处理加入到 login-webflow.xml 请求流中:
<on-start> <evaluate expression="initialFlowSetupAction" /> </on-start> <!-- 添加如下配置 :--> <action-state id="provideLoginTicket"> <evaluate expression="provideLoginTicketAction"/> <transition on="loginTicketRequested" to ="viewRedirectToRequestor" /> <transition on="continue" to="ticketGrantingTicketExistsCheck" /> </action-state> <view-state id="viewRedirectToRequestor" view="casRedirectToRequestorView" model="credentials"> <var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" /> <binder> <binding property="username" /> <binding property="password" /> </binder> <on-entry> <set name="viewScope.commandName" value="'credentials'" /> </on-entry> <transition on="submit" bind="true" validate="true" to="realSubmit"> <set name="flowScope.credentials" value="credentials" /> <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" /> </transition> </view-state> <!---添加结束处 ---> <decision-state id="ticketGrantingTicketExistsCheck"> <if test="flowScope.ticketGrantingTicketId neq null" then="hasServiceCheck" else="gatewayRequestCheck" /> </decision-state> <!-- ..... 省略中间代码 ...--> <action-state id="realSubmit"> <evaluate expression="authenticationViaFormAction.submit(flowRequestContext, flowScope.credentials, messageContext)" /> <transition on="warn" to="warn" /> <transition on="success" to="sendTicketGrantingTicket" /> <transition on="error" to="viewLoginForm" /> <!--加入该transition , 当验证失败之后重新获取login ticket --> <transition on="errorForRemoteRequestor" to="viewRedirectToRequestor" /> </action-state>
好了,至此,对server端的调整基本上已经大功告成了,现在开始写一个测试远程登录的 html:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Test remote Login using JS</title> <script type="text/javascript"> function prepareLoginForm() { $('myLoginForm').action = casLoginURL; $("lt").value = loginTicket; } function checkForLoginTicket() { var loginTicketProvided = false; var query = ''; casLoginURL = 'http://192.168.6.1:8080/member/login'; thisPageURL = 'http://192.168.6.1:8080/member/test-login.html'; casLoginURL += '?login-at=' + encodeURIComponent (thisPageURL); query = window.location.search; query = query.substr (1); var param = new Array(); //var value = new Array(); var temp = new Array(); param = query.split ('&'); i = 0; // 开始获取当前 url 的参数,获到 lt 和 error_message。 while (param[i]) { temp = param[i].split ('='); if (temp[0] == 'lt') { loginTicket = temp[1]; loginTicketProvided = true; } if (temp[0] == 'error_message') { error = temp[1]; } i++; } // 判断是否已经获取到 lt 参数,如果未获取到则跳转至 cas/login 页,并且带上请求参数 get-lt=true。 第一次进该页面时会进行一次跳转 if (!loginTicketProvided) { location.href = casLoginURL + '&get-lt=true'; } } var $ = function(id){ return document.getElementById(id); } checkForLoginTicket(); onload = prepareLoginForm; </script> </head> <body> <h2>Test remote Login using JS</h2> <form id="myLoginForm" action="" method="post"> <input type="hidden" name="_eventId" value="submit" /> <table> <tr> <td id="txt_error" colspan="2"> <script type="text/javascript" language="javascript"> <!-- if ( error ) { error = decodeURIComponent (error); document.write (error); } //--> </script> </td> </tr> <tr> <td>Username:</td> <td><input type="text" value="" name="username" ></td> </tr> <tr> <td>Password:</td> <td><input type="text" value="" name="password" ></td> </tr> <tr> <td>Login Ticket:</td> <td><input type="text" name="lt" id="lt" value=""></td> </tr> <tr> <td>Service:</td> <td><input type="text" name="service" value="http://www.google.com.hk"></td> </tr> <tr> <td align="right" colspan="2"><input type="submit" /></td> </tr> </table> </form> </body> </html>
开始测试,直接访问:http://192.168.6.1:8080/member/test-login.html 发现进行了二次重定向,进入该页面 js 未发现 lt 参数,于是重定向到 http://192.168.6.1:8080/member/login?login-at=http://192.168.6.1:8080/member/test-login.html &get-lt=true ,然后又从该页重定向到 http://192.168.6.1:8080/member/test-login.html?lt=e1s1 ,可以发现,其中的 lt 就是我们所需要的 login ticket参数。
6. 不足之处
1. 可以发现,每次用户访问 登录页面时都要进行两次重定向的操作,虽然很快,但是在有些情况仍然能看到登录页面闪了一下。 当然这也是有办法可以解决的!
2. 可以发现,当登录失败之后,会将错误信息以参数的方式进行传递,看上去这并非专业做法。可以定义一些错误标识,比如 1 是用户名或密码错误之类的。
PS:参考:https://wiki.jasig.org/display/CAS/Using+CAS+without+the+Login+Screen 如有不足之处,欢迎指正~
评论
45 楼
denger
2014-03-17
liuzhou0117 写道
楼主,你好:
不知道你是否碰到客户端网站游客页的问题,就是客户端网站有些页面是不需要登录也可以访问的。而现在有这样一个案例,用户同时打开配置了sso的两个网站,都是游客页,在a网站登录了,然后刷新b网站的游客页,需要显示用户已登录。我现在的做法是在客户端的filter中加入配置例外,如果请求是在例外之内的,就不让请求重定向到服务端去,但是这样也就带来了上面的那个案例中刷新游客页面得不到用户信息的问题,期待楼主来一起讨论。
不知道你是否碰到客户端网站游客页的问题,就是客户端网站有些页面是不需要登录也可以访问的。而现在有这样一个案例,用户同时打开配置了sso的两个网站,都是游客页,在a网站登录了,然后刷新b网站的游客页,需要显示用户已登录。我现在的做法是在客户端的filter中加入配置例外,如果请求是在例外之内的,就不让请求重定向到服务端去,但是这样也就带来了上面的那个案例中刷新游客页面得不到用户信息的问题,期待楼主来一起讨论。
如果是游客页的话,不需要将 URL 放在 filter 中。 只需要在 Caserver 提供一下获取当前登录用户的 接口,然后在 游客页通过 AJAX 去请求获取即可。
可以看看 taobao 的做法, www.taobao.com 如果你已经登录的话,就会在头部显示当前用户名。通过 cookie 或 API 可以实现此需求。
44 楼
liuzhou0117
2014-03-16
楼主,你好:
不知道你是否碰到客户端网站游客页的问题,就是客户端网站有些页面是不需要登录也可以访问的。而现在有这样一个案例,用户同时打开配置了sso的两个网站,都是游客页,在a网站登录了,然后刷新b网站的游客页,需要显示用户已登录。我现在的做法是在客户端的filter中加入配置例外,如果请求是在例外之内的,就不让请求重定向到服务端去,但是这样也就带来了上面的那个案例中刷新游客页面得不到用户信息的问题,期待楼主来一起讨论。
不知道你是否碰到客户端网站游客页的问题,就是客户端网站有些页面是不需要登录也可以访问的。而现在有这样一个案例,用户同时打开配置了sso的两个网站,都是游客页,在a网站登录了,然后刷新b网站的游客页,需要显示用户已登录。我现在的做法是在客户端的filter中加入配置例外,如果请求是在例外之内的,就不让请求重定向到服务端去,但是这样也就带来了上面的那个案例中刷新游客页面得不到用户信息的问题,期待楼主来一起讨论。
43 楼
hjysuccess
2013-11-27
hjysuccess 写道
hjysuccess 写道
请问<action-state id="provideLoginTicket">的开始节点在哪里配置的呢?
已解决,放到前面就好了。
总是返回<script>window.location.href = "/member/login";</script>
取不到lt
42 楼
hjysuccess
2013-11-27
hjysuccess 写道
请问<action-state id="provideLoginTicket">的开始节点在哪里配置的呢?
已解决,放到前面就好了。
41 楼
hjysuccess
2013-11-27
请问<action-state id="provideLoginTicket">的开始节点在哪里配置的呢?
40 楼
sanyaocun000
2013-11-14
为什么每次登录后都要去认证中心的登录页面再次登录呢?
39 楼
sanyaocun000
2013-11-13
http://cas.my.com:8088/casServer/login?login-at=http%3A%2F%2Fcas.my.com%3A8080%2Fclient3%2Flogin.jsp&get-lt=true
配置后访问执行了跳转
http://cas.my.com:8088/casServer/login?login-at=http://192.168.6.1:8080/member/test-login.html &get-lt=true,但是没有重定向到 http://cas.my.com:8080/member/test-login.html?lt=e1s1
38 楼
xiosu121
2013-11-04
感谢lz的分享,参考您的文章,我在casServer3.5.0版本中实现了类似功能,并作了整理,与大家一起分享一下http://water123.net/thread-131-1-1.html
37 楼
673972360
2013-08-16
lz,按您这样做登录成功后还是跳转到cas默认的登录成功页,而没有跳转到子系统,请问这该如何解决,我看了一下,在AuthenticationViaFormAction 里的 submit(...)方法里 final Service service = WebUtils.getService(context); service 为null ,请问有解决的办法吗?期待楼主回应啊
36 楼
wangxing870555
2013-07-09
54zzb 写道
通过楼主的配置,我同样实现了相应的客户端登陆界面改写,成功执行了与楼主一样的效果。
感谢楼主精彩的分享,但是还是有点遗憾,楼主您的文章在编写测试html代码时是有问题的,需要修改才能正常执行,其他都是没问题的,在此我就献丑帮楼主提醒下其他人。
楼主的html代码是有点问题的,都集中在
test-login.html,这个文件中,需要修改的地方如下:
1.jquery语法错误,且头文件未引入jquery控件
建议改为原生js应用:
function prepareLoginForm() {
document.getElementById("myLoginForm").action = casLoginURL;
document.getElementById("lt").value = loginTicket;
}
如果要用$(),那么需要引入jquery.js以及应该增加“#”,即改为
$('#myLoginForm').action = casLoginURL;
$("#lt").value = loginTicket;
2.这个我想楼主应该是改过tomcat的端口配置,那我把我的写下了,供大家参考
casLoginURL = 'https://sso.zzb.com:8443/cas/login';//这个为cas的统一认证url
thisPageURL = 'http://localhost:8080/cas/test-login.html';//自定义登录界面
3.应该是楼主代码复制时出现的问题
queryquery = query.substr (1);
应该改为query = query.substr(1);
要改的地方就这三个,其他地方按照楼主的来配是绝对可以成功的,当然有些细节还是要根据自己的来改的,如package的路径等com.denger.sso.util.CasUtility
感谢楼主精彩的分享,但是还是有点遗憾,楼主您的文章在编写测试html代码时是有问题的,需要修改才能正常执行,其他都是没问题的,在此我就献丑帮楼主提醒下其他人。
楼主的html代码是有点问题的,都集中在
test-login.html,这个文件中,需要修改的地方如下:
1.jquery语法错误,且头文件未引入jquery控件
建议改为原生js应用:
function prepareLoginForm() {
document.getElementById("myLoginForm").action = casLoginURL;
document.getElementById("lt").value = loginTicket;
}
如果要用$(),那么需要引入jquery.js以及应该增加“#”,即改为
$('#myLoginForm').action = casLoginURL;
$("#lt").value = loginTicket;
2.这个我想楼主应该是改过tomcat的端口配置,那我把我的写下了,供大家参考
casLoginURL = 'https://sso.zzb.com:8443/cas/login';//这个为cas的统一认证url
thisPageURL = 'http://localhost:8080/cas/test-login.html';//自定义登录界面
3.应该是楼主代码复制时出现的问题
queryquery = query.substr (1);
应该改为query = query.substr(1);
要改的地方就这三个,其他地方按照楼主的来配是绝对可以成功的,当然有些细节还是要根据自己的来改的,如package的路径等com.denger.sso.util.CasUtility
你好,能把你改造成功后的cas server端代码给我发一份好吗?QQ:675046199@qq.com,多谢了。
35 楼
TheUniqueGirl
2013-05-06
TheUniqueGirl 写道
snowspice 写道
snowspice 写道
我按配置操作了下,但是在自定义流程这里出现问题,
从loginTicketRequested 跳转到viewRedirectToRequestor,这里跳不过去,出现了死循环,希望博主能解答下吗。
<action-state id="provideLoginTicket"> <evaluate expression="provideLoginTicketAction"/> <transition on="loginTicketRequested" to ="viewRedirectToRequestor" /> <transition on="continue" to="ticketGrantingTicketExistsCheck" /> </action-state> <view-state id="viewRedirectToRequestor" view="casRedirectToRequestorView" model="credentials"> <var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" /> <binder> <binding property="username" /> <binding property="password" /> </binder> <on-entry> <set name="viewScope.commandName" value="'credentials'" /> </on-entry> <transition on="submit" bind="true" validate="true" to="realSubmit"> <set name="flowScope.credentials" value="credentials" /> <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" /> </transition> </view-state>
从loginTicketRequested 跳转到viewRedirectToRequestor,这里跳不过去,出现了死循环,希望博主能解答下吗。
--死循环问题解决,是由于copy时,view.property中多了空格,导致死循环,
--但是登录时,传递的service对象为空。导致,不能跳转到我指定的页面上。
我的也出现了循环链问题,copy的时候带有空格,将default_views.properties中拷贝过去的内容去掉后面的空格就ok了,感谢这个兄弟。
后面的service为空的问题: 发现flowscope.service == null,那个service参数没有获取到。 可以这样修改一下:
test-login.html中:
casLoginURL = 'http://192.168.1.104:8080/CasResearch/login?service=http://www.sina.com';
casLoginURL += '[color=red]&[/color]login-at=' + encodeURIComponent (thisPageURL);
这样修改一下就可以成功跳转到新浪首页了。
34 楼
TheUniqueGirl
2013-05-06
snowspice 写道
snowspice 写道
我按配置操作了下,但是在自定义流程这里出现问题,
从loginTicketRequested 跳转到viewRedirectToRequestor,这里跳不过去,出现了死循环,希望博主能解答下吗。
<action-state id="provideLoginTicket"> <evaluate expression="provideLoginTicketAction"/> <transition on="loginTicketRequested" to ="viewRedirectToRequestor" /> <transition on="continue" to="ticketGrantingTicketExistsCheck" /> </action-state> <view-state id="viewRedirectToRequestor" view="casRedirectToRequestorView" model="credentials"> <var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" /> <binder> <binding property="username" /> <binding property="password" /> </binder> <on-entry> <set name="viewScope.commandName" value="'credentials'" /> </on-entry> <transition on="submit" bind="true" validate="true" to="realSubmit"> <set name="flowScope.credentials" value="credentials" /> <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" /> </transition> </view-state>
从loginTicketRequested 跳转到viewRedirectToRequestor,这里跳不过去,出现了死循环,希望博主能解答下吗。
--死循环问题解决,是由于copy时,view.property中多了空格,导致死循环,
--但是登录时,传递的service对象为空。导致,不能跳转到我指定的页面上。
我的也出现了循环链问题,copy的时候带有空格,将default_views.properties中拷贝过去的内容去掉后面的空格就ok了,感谢这个兄弟。
33 楼
denger
2013-04-10
@54zzb 不错,建议把你的最新实现开源出来,放在 github 上!
32 楼
54zzb
2013-04-10
通过楼主的配置,我同样实现了相应的客户端登陆界面改写,成功执行了与楼主一样的效果。
感谢楼主精彩的分享,但是还是有点遗憾,楼主您的文章在编写测试html代码时是有问题的,需要修改才能正常执行,其他都是没问题的,在此我就献丑帮楼主提醒下其他人。
楼主的html代码是有点问题的,都集中在
test-login.html,这个文件中,需要修改的地方如下:
1.jquery语法错误,且头文件未引入jquery控件
建议改为原生js应用:
function prepareLoginForm() {
document.getElementById("myLoginForm").action = casLoginURL;
document.getElementById("lt").value = loginTicket;
}
如果要用$(),那么需要引入jquery.js以及应该增加“#”,即改为
$('#myLoginForm').action = casLoginURL;
$("#lt").value = loginTicket;
2.这个我想楼主应该是改过tomcat的端口配置,那我把我的写下了,供大家参考
casLoginURL = 'https://sso.zzb.com:8443/cas/login';//这个为cas的统一认证url
thisPageURL = 'http://localhost:8080/cas/test-login.html';//自定义登录界面
3.应该是楼主代码复制时出现的问题
queryquery = query.substr (1);
应该改为query = query.substr(1);
要改的地方就这三个,其他地方按照楼主的来配是绝对可以成功的,当然有些细节还是要根据自己的来改的,如package的路径等com.denger.sso.util.CasUtility
感谢楼主精彩的分享,但是还是有点遗憾,楼主您的文章在编写测试html代码时是有问题的,需要修改才能正常执行,其他都是没问题的,在此我就献丑帮楼主提醒下其他人。
楼主的html代码是有点问题的,都集中在
test-login.html,这个文件中,需要修改的地方如下:
1.jquery语法错误,且头文件未引入jquery控件
建议改为原生js应用:
function prepareLoginForm() {
document.getElementById("myLoginForm").action = casLoginURL;
document.getElementById("lt").value = loginTicket;
}
如果要用$(),那么需要引入jquery.js以及应该增加“#”,即改为
$('#myLoginForm').action = casLoginURL;
$("#lt").value = loginTicket;
2.这个我想楼主应该是改过tomcat的端口配置,那我把我的写下了,供大家参考
casLoginURL = 'https://sso.zzb.com:8443/cas/login';//这个为cas的统一认证url
thisPageURL = 'http://localhost:8080/cas/test-login.html';//自定义登录界面
3.应该是楼主代码复制时出现的问题
queryquery = query.substr (1);
应该改为query = query.substr(1);
要改的地方就这三个,其他地方按照楼主的来配是绝对可以成功的,当然有些细节还是要根据自己的来改的,如package的路径等com.denger.sso.util.CasUtility
31 楼
fangxia123
2013-03-15
配置后访问执行了跳转
http://192.168.6.1:8080/member/login?login-at=http://192.168.6.1:8080/member/test-login.html &get-lt=true,但是没有重定向到 http://192.168.6.1:8080/member/test-login.html?lt=e1s1 反而跳转到cas的登录页面
http://192.168.6.1:8080/member/login?login-at=http://192.168.6.1:8080/member/test-login.html &get-lt=true,但是没有重定向到 http://192.168.6.1:8080/member/test-login.html?lt=e1s1 反而跳转到cas的登录页面
30 楼
fangxia123
2013-03-15
timeroading1 写道
lz,您好,按你这种方式,我试了一下。针对3.4.11版本的,login-flow.xml是不是得调一下呢?test-login.html提交按钮时,为什么老是提交到cas的login那呢?。还望指教。
29 楼
xiaokang1582830
2012-10-11
配置后访问执行了跳转
http://192.168.6.1:8080/member/login?login-at=http://192.168.6.1:8080/member/test-login.html &get-lt=true,但是没有重定向到 http://192.168.6.1:8080/member/test-login.html?lt=e1s1
http://192.168.6.1:8080/member/login?login-at=http://192.168.6.1:8080/member/test-login.html &get-lt=true,但是没有重定向到 http://192.168.6.1:8080/member/test-login.html?lt=e1s1
28 楼
soflytanny
2012-07-24
兄台, 你这个还存在另一个问题,
获到IT以后,直接以form的方式再将usernaem,pwd,it等参数提交至/member/login,这个时候cas是需要跟你本地的cookie交互的,
在此例中,你的client与CAS Service在同域自然成功,
casLoginURL = 'http://192.168.6.1:8080/member/login';
thisPageURL = 'http://192.168.6.1:8080/member/test-login.html';
但如果是跨域,登陆是不会成功,不知兄台如何考虑这个问题的
获到IT以后,直接以form的方式再将usernaem,pwd,it等参数提交至/member/login,这个时候cas是需要跟你本地的cookie交互的,
在此例中,你的client与CAS Service在同域自然成功,
casLoginURL = 'http://192.168.6.1:8080/member/login';
thisPageURL = 'http://192.168.6.1:8080/member/test-login.html';
但如果是跨域,登陆是不会成功,不知兄台如何考虑这个问题的
27 楼
snowspice
2012-05-28
snowspice 写道
我按配置操作了下,但是在自定义流程这里出现问题,
从loginTicketRequested 跳转到viewRedirectToRequestor,这里跳不过去,出现了死循环,希望博主能解答下吗。
<action-state id="provideLoginTicket"> <evaluate expression="provideLoginTicketAction"/> <transition on="loginTicketRequested" to ="viewRedirectToRequestor" /> <transition on="continue" to="ticketGrantingTicketExistsCheck" /> </action-state> <view-state id="viewRedirectToRequestor" view="casRedirectToRequestorView" model="credentials"> <var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" /> <binder> <binding property="username" /> <binding property="password" /> </binder> <on-entry> <set name="viewScope.commandName" value="'credentials'" /> </on-entry> <transition on="submit" bind="true" validate="true" to="realSubmit"> <set name="flowScope.credentials" value="credentials" /> <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" /> </transition> </view-state>
从loginTicketRequested 跳转到viewRedirectToRequestor,这里跳不过去,出现了死循环,希望博主能解答下吗。
--死循环问题解决,是由于copy时,view.property中多了空格,导致死循环,
--但是登录时,传递的service对象为空。导致,不能跳转到我指定的页面上。
26 楼
snowspice
2012-05-27
我按配置操作了下,但是在自定义流程这里出现问题,
从loginTicketRequested 跳转到viewRedirectToRequestor,这里跳不过去,出现了死循环,希望博主能解答下吗。
<action-state id="provideLoginTicket"> <evaluate expression="provideLoginTicketAction"/> <transition on="loginTicketRequested" to ="viewRedirectToRequestor" /> <transition on="continue" to="ticketGrantingTicketExistsCheck" /> </action-state> <view-state id="viewRedirectToRequestor" view="casRedirectToRequestorView" model="credentials"> <var name="credentials" class="org.jasig.cas.authentication.principal.UsernamePasswordCredentials" /> <binder> <binding property="username" /> <binding property="password" /> </binder> <on-entry> <set name="viewScope.commandName" value="'credentials'" /> </on-entry> <transition on="submit" bind="true" validate="true" to="realSubmit"> <set name="flowScope.credentials" value="credentials" /> <evaluate expression="authenticationViaFormAction.doBind(flowRequestContext, flowScope.credentials)" /> </transition> </view-state>
从loginTicketRequested 跳转到viewRedirectToRequestor,这里跳不过去,出现了死循环,希望博主能解答下吗。
发表评论
-
关于 CAS SSO 文章声明
2015-03-21 14:39 3115由于几年前写了几篇 CAS 系列的文章,之后陆续有人参照文章去 ... -
CAS 之 跨域 Ajax 登录实践
2011-07-08 01:36 27524因最近经常有时候被一些朋友问到关于 CAS 跨全域下的 Aja ... -
新浪微博如何实现 SSO 的分析
2011-05-10 14:44 24726最近在使用sina微博时,经常性交替使用 weibo ... -
淘宝如何跨域获取Cookie分析
2011-04-13 10:39 20431Move to: http://www.iteye.com/t ... -
CAS 之 集成RESTful API
2011-03-23 20:59 44207最近因为公司另一款基于C/S的产品也需要整合到CAS ... -
CAS 之 实现用户注册后自动登录
2010-11-08 16:22 185971. 关于CAS的介绍不再累述,我想涉及过SSO同学 ...
相关推荐
【标题】"CAS修改登录页"是一个针对中央认证服务(Central Authentication Service,简称CAS)的定制化实践。在单点登录(Single Sign-On,SSO)系统中,CAS扮演着核心角色,它提供了统一的身份验证服务,使得用户只...
CAS(Central Authentication Service)是Java开发的一个开源的单点登录...通过学习和实践,你可以掌握CAS的核心概念,实现自定义认证策略,以及优化客户端集成,从而为你的项目构建一个强大而安全的单点登录系统。
标题中的“让CAS支持客户端自定义登陆页面——客户端篇”表明了本文主要探讨的是如何在中央认证服务(Central Authentication Service, CAS)系统中,允许客户端应用程序实现自定义登录页面的配置与实现。CAS是一个...
9. **API扩展**:如果需要在登录页面添加自定义功能,如集成第三方服务,可以通过实现 CAS 提供的 REST API 或者 WebService API 来实现。 10. **文档更新**:任何代码更改后,确保更新相关的开发者文档,以便团队...
总结,实现CAS系统下不同应用展示不同登录页的关键在于理解CAS的工作机制,并对服务器端进行适当的配置和扩展。通过修改登录视图、动态选择页面和定义应用标识,我们可以为用户提供更加个性化和友好的登录体验。在...
由于实际内容没有给出,我将基于常见的CAS自定义登录流程进行讲解。 首先,理解CAS的工作原理至关重要。当用户尝试访问一个受CAS保护的应用时,会被重定向到CAS服务器的登录页面。在这里,用户输入凭证,如用户名和...
这通常涉及向CAS服务器发送请求,获取认证URL(即CAS登录页),并在用户登录成功后,处理CAS返回的服务票证。 4. iframe技术:使用HTML的iframe元素,将CAS的登录页面嵌入到你的应用中,使得用户可以在不离开当前...
本文主要介绍如何让CAS(Central Authentication Service)支持客户端自定义登录页面,主要集中在服务器端的修改。CAS是一种开源的身份验证框架,它提供单点登录(SSO)功能,通常用于集中管理多个应用系统的用户...
本文将详细介绍如何在CAS服务器端进行配置,以便支持客户端自定义登录页面。 首先,我们要明确修改的目标是不影响CAS原有的统一登录界面功能,同时尽可能简化客户端的实现,并确保原有功能的安全性。但要注意的是,...
在本文中,我们将深入探讨CAS单点登录的基本原理、工作流程以及如何通过提供的Demo进行实践操作。 **CAS基本原理** CAS的核心思想是用户只需在一个应用系统中验证身份,之后访问其他所有支持CAS的应用系统时都不再...
可以使用CAS提供的工具或者开发自定义的测试脚本来模拟用户登录和应用间的跳转。 在提供的PDF文件`cas单点登录(一).pdf`和`cas单点登录(二).pdf`中,应该详细涵盖了这些步骤,以及更深入的技术细节,包括可能...
**CAS单点登录配置大全** CAS(Central Authentication Service,中央认证服务)是一种广泛使用的开源单点登录(Single Sign-On,SSO)协议。它允许用户通过一个统一的认证系统访问多个应用系统,而无需在每个系统...
**基于Cas的单点登录实现** 单点登录(Single Sign-On,简称SSO)是一种在多个应用系统中,...通过学习和实践这个示例应用,开发者可以深入理解Cas和Shiro的结合使用,以及SSO在实际项目中的应用,提升系统安全性。
CAS(Central Authentication Service)是...总之,"cas单点登录4.0"的资源对于学习和实践CAS单点登录系统非常重要。无论是部署和配置CAS服务器,还是深入研究其源代码,都能帮助我们更全面地理解和掌握单点登录技术。
总结,通过学习和实践这个"利用CAS实现单点登录的完整实例",你将掌握如何使用Jasig CAS构建一个高效的单点登录系统,从而提升用户体验,简化身份验证管理,并加强系统的安全性。记得深入理解每个步骤,并根据实际...
在这个" CAS单点登录示例 "中,你可以通过实践来理解这些概念,探索如何设置CAS服务器,配置客户端,以及如何进行用户认证。通过这个示例,你将更深入地了解SSO的工作原理,为实际项目中的身份验证解决方案打下坚实...
6. **定制化**:根据应用需求,可能需要自定义CAS客户端的行为,如自定义登录页面、错误处理或者用户信息的解析。 7. **安全考虑**:集成CAS后,应确保网络通信的安全,通常采用HTTPS协议来加密传输数据。同时,对...
通过"SSO之CAS单点登录实例演示",我们可以实践这些步骤,了解如何设置和运行一个基本的CAS环境,进一步理解SSO的工作原理和实际应用。这个实例将帮助我们更好地掌握如何为自己的应用实现SSO功能,提升系统的安全性...
[置顶] SSO单点登录系列3:cas-server端配置认证方式实践(数据源+自定义java类认证) http://blog.csdn.net/ae6623/article/details/8851801 [置顶] SSO单点登录系列2:cas客户端和cas服务端交互原理动画图解,cas...