CAS利用Iframe框架跨域Ajax登录
因最近经常有时候被一些朋友问到关于 CAS 跨全域下的 Ajax 登录方式实现,正好之前也分析Sina微博的SSO实现,文中也说了 SINA 的 SSO 实际上(或机制)直接使用了 CAS 这个开源项目。于是本文中要说的CAS AJAX登录方式便参考了 SINA 的AJAX登录实现。 关于具体方案,CAS官方上好象没有提供相关说明,倒是有一文说到 Without the Login Screen(详情参见 CAS 之自定义登录页实践),其具体实现方式甚是麻烦,又是改源码,又是通过JS跳转,又是一堆配置。 当然,虽然如此,但该文中所提到的获取 login tikcet 的方式还是值的参考的,因为无论什么方式登录,前提是必须获取到该ticket才允许登录验证。
虽然这里所说的主要是针对 CAS,其实具体的实现方式中有些还是值得参考的,如跨域设置 cookie, jsonp + iframe 跨域异步请求、P3P 及 关于 spring webflow 等其它相关的一些信息。
思路
关于具体的实现思路基本上都是参考了 SINA,所以详细信息可以在 分析Sina微博的SSO实现 看到 或 自己去 firebug 一下 sina micro-blog。
虽然这里所说的主要是针对 CAS,其实具体的实现方式中有些还是值得参考的,如跨域设置 cookie, jsonp + iframe 跨域异步请求、P3P 及 关于 spring webflow 等其它相关的一些信息。
思路
关于具体的实现思路基本上都是参考了 SINA,所以详细信息可以在 分析Sina微博的SSO实现 看到 或 自己去 firebug 一下 sina micro-blog。
实践
Environment:
cas-server-3.4.2.1 www.passport:8080/cas/
cas-client-3.1.10 www.portal:8080/login
以上域名是方便测试跨域,故修改本机 hosts。
Step 1: 在首次进入登录时(portal域中/login),通过 JSONP 从 passport 域中获取 login ticket。
登录表单:
Html代码
1. <form action="www.passport:8080/cas/login" method="post" onsubmit="retur
n loginValidate();" target="ssoLoginFrame">
2. <ul>
3. <span class="red" style="height:12px;" id="J_ErrorMsg"></span>
4.
5. <li>
6. <em>用户名:</em>
7. <input name="username" id="J_Username" type="text" autocomplete="off" class="line" style="width: 180px" />
8. </li>
9. <li>
10. <em>密 码:</em>
11. <input name="password" type="password" id="J_Password" class="line" style="width: 180px" />
12. </li>
13.
14. <li class="mai">
15. <em> </em>
16. <input type="checkbox" name="rememberMe" id="rememberMe" value="true"/>
17. 自动登录
18. <a href="/retrieve">忘记密码?</a>
19. </li>
20. <li>
21. <em> </em>
22. <input type="hidden" name="isajax" value="true" />
23. <input type="hidden" name="isframe" value="true" />
24. <input type="hidden" name="lt" value="" id="J_LoginTicket">
25. <input type="hidden" name="_eventId" value="submit" />
26. <input name="" type="submit" value="登录" class="loginbanner" />
27. </li>
28. </ul>
29. </form>
Js代码
1. $(document).ready(function(){
2. flushLoginTicket(); // 进入登录页,则获取login ticket,该函数在下面定义。
3. });
关于 cas-server 如何返回 lt ,在 Without the Login Screen 文章中有提到。
Step 2: 输入用户名密码,提交验证。将表单信息将会被POST提交至 动态的iframe中,定义该登录页面中登录后的处理逻辑。
Step 2: 输入用户名密码,提交验证。将表单信息将会被POST提交至 动态的iframe中,定义该登录页面中登录后的处理逻辑。
Js代码
1. // 登录验证函数, 由 onsubmit 事件触发
2. var loginValidate = function(){
3. var msg;
4. if ($.trim($('#J_Username').val()).length == 0 ){
5. msg = "用户名不能为空。";
6. } else if ($.trim($('#J_Password').val()).length == 0 ){
7. msg = "密码不能为空。";
8. }
9. if (msg && msg.length > 0) {
10. $('#J_ErrorMsg').fadeOut().text(msg).fadeIn();
11. return false;
12. // Can't request the login ticket.
13. } else if ($('#J_LoginTicket').val().length == 0){
14. $('#J_ErrorMsg').text('服务器正忙,请稍后再试..');
15. return false;
16. } else {
17. // 验证成功后,动态创建用于提交登录的 iframe
18. $('body').append($('<iframe/>').attr({
19. style: "display:none;width:0;height:0",
20. id: "ssoLoginFrame",
21. name: "ssoLoginFrame",
22. src: "javascript:false;"
23. }));
24. return true;
25. }
26. }
27.
28. // 登录处理回调函数,将由 iframe 中的页同自动回调
29. var feedBackUrlCallBack = function (result) {
30. customLoginCallBack(result);
31. deleteIFrame('#ssoLoginFrame');// 删除用完的iframe,但是一定不要在回调前删除,Firefox可能有问题的
32. };
33.
34. // 自定义登录回调逻辑
35. var customLoginCallBack = function(result){
36. // 登录失败,显示错误信息
37. if (result.login == 'fails'){
38. $('#J_ErrorMsg').fadeOut().text(result.msg).fadeIn();
39. // 重新刷新 login ticket
iframe参数传递40. flushLoginTicket();
41. }
42. // do&
43. }
44.
45. var deleteIFrame = function (iframeName) {
46. var iframe = $(iframeName);
47. if (iframe) { // 删除用完的iframe,避免页面刷新或前进、后退时,重复执行该iframe的请求
48. ve()
49. }
50. };
51.
52. // 由于一个 login ticket 只允许使用一次, 当每次登录需要调用该函数刷新 lt
53. var flushLoginTicket = function(){
54. var _services = 'service=' + encodeURIComponent('www.portal:8080/uc/');
55. $.getScript('www.passport:8080/cas/login?'+_services+'&get-lt=true&n='
56. + new Date().getTime(),
57. function(){
58. // 将返回的 _loginTicket 变量设置到 input name="lt" 的value中。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论