自定义客户端登录CAS服务器-iframe实现

阅读更多
环境:
tomcat7.05
cas-server-3.4.5
cas-client-3.2.0

呃,你没看错,是用iframe实现。这个不算是一个好的方案,甚至我自己都有点看不起自己的感觉。但却是一个简单易用并最能兼容以后CAS-server更新的一套方案(还用说么,你都用iframe了)。目前项目比较紧急没时间去研究Spring WebFlow 3的情况下只好出此下策了,大神请喷。

这个题目相信使用过CAS的朋友都不会陌生了。由于安全性的问题,CAS-Server 一直不建议把验证放到客户端之上。所以不提供验证表单的接口,或者说必须我们去开发扩展。而在实际应用中,很多单点登录的表单却是在客户端中完成,例如在某门户首页的登陆框。这些是不可能在Cas-Server上直接改造成门户的。所以造成了必须在门户中进行CAS服务器表单验证的局面。

当然这一切都是建立在我目前对CAS的熟悉程度来说的,欢迎指教。

其实网上也有比较多的方案,但基本上是版本对不上了,我也逼于无奈才采取这种比较傻瓜式的方法进行验证。

不管怎样,虽然觉得说名字大家都知道实现原理了,但也应该照顾一些不理解的。

1.自己的登录页面中用iframe加载cas-server的登录页面。
2.当用户输入账号密码登录的时候,同时把账号密码信息传入cas-server登录页面,并且提交。
3.若成功则刷新页面,登录窗口消失。若失败则提示用户。这个iframe相对用户来说是不可见的。

引用一下前辈的客户端实现目标描述:
引用
客户端实现目标

客户端实现主要需要满足5个case:

1. 用户未在中央认证服务器登陆,访问客户端受保护资源时,客户端重定向到中央认证服务器请求TGT认证,认证失败,转回客户端登陆页面,保证受保护资源URL信息不丢失
2. 用户未在中央认证服务器登陆,访问客户端登陆页面时,客户端重定向到中央认证服务器请求TGT认证,认证失败,转回客户端登陆页面,此次登录页面不再受保护,允许访问
3. 用户已在中央认证服务器登陆,访问客户端受保护资源时,客户端重定向到中央认证服务器请求TGT认证,认证成功,直接转回受保护资源
4. 用户在客户端登陆页面提交用户名密码,客户端将用户名密码信息提交给服务器端,认证失败,转回客户端登陆页面,携带失败信息并保证转到登陆页面前受保护资源URL信息不丢失
5. 用户在客户端登陆页面提交用户名密码,客户端将用户名密码信息提交给服务器端,认证成功,转回转到登陆页面前受保护资源


而技术方面没什么太大的要求,最主要是一些基本的javascript知识。

一、改造Cas-Server默登陆页面,让它对反馈信息支持。

打开 WEB-INF\view\jsp\default\ui\casLoginView.jsp
之上加上以下代码

<%-- add by Kenny Begin --%>

<%-- add by Kenny End --%>


其中cas_serverFrame为我自定义登陆页面中iframe的id,稍后会看到。判断其实可以简化些,或者其他可以自由发挥了,供参考。

查找页面中的submit表单提交按钮,如果name为submit的话记得改掉(默认是name=submit), 因为如果在html中有任何一个元素的name属性为submit时,则用javascript操作form元素时是无法执行submit(),会提示'不存在的方法'。这个卡了我不少时间。

二、门户中自定义登陆表单页面

<%-- 
    Document   : login
    Created on : 2011-1-11, 3:07:16
    Author     : Kenny
--%>

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>


    
    远程CAS客户端登陆页面
    
    


    

远程CAS客户端登陆页面

<% if (request.getRemoteUser() == null) { %>
用户名:
密  码:
<% } else { %>
您好:<%= request.getRemoteUser() %>
<% } %>


三、登陆页面中用到的clientLogin.js

var constants = {
    loginButt : 'loginButt',
    clientLoginForm : 'myLoginForm',
    casServerFrame : 'cas_serverFrame',
    loginFormUser : 'username',
    loginFormPassword : 'password',
    serverLoginFormId : 'fm1',
    redirectURLName : 'service',
    loginURL : 'https://localhost:8443/sso_demo/login.jsp',
    casServerURL : 'https://localhost:8443/cas-server/login'
}

function initEvents(e){
    var loginButtEl = document.getElementById(constants.loginButt);
    if(loginButtEl){
        registerListener(loginButtEl, 'click', loginCAS);
    }
    var loginFormEl = document.getElementById(constants.clientLoginForm);
    if(loginFormEl){
        registerListener(loginFormEl, 'keydown', function(e){
            if(isKeyDownEnter(e)){
                loginCAS();
            }
        });
    }
}

loginCAS  = function(){
    var username = document.getElementById(constants.loginFormUser).value;
    var password = document.getElementById(constants.loginFormPassword).value;
    var casServerFrameDoc = document.getElementById(constants.casServerFrame).contentWindow.document;
    var cas_username = casServerFrameDoc.getElementById(constants.loginFormUser);
    var cas_password = casServerFrameDoc.getElementById(constants.loginFormPassword);
    cas_username.value = username;
    cas_password.value = password;
    var cas_loginForm = casServerFrameDoc.forms[constants.serverLoginFormId];
    if(cas_loginForm){
        cas_loginForm.submit();
    }else{
        alert('cas_loginForm is undefined');
    }
}

function resetWindow(){
    if (top.location !== self.location) {
        top.location = self.location;
    }
}

function loadedIFrame(e){
    var frameURL = constants.casServerURL;
//    frameURL += '?service=';
//    var redirectURL = getParam(constants.redirectURLName);
//    redirectURL = redirectURL ? redirectURL : constants.loginURL;
//    frameURL += redirectURL;
    var cas_serverFrame = document.getElementById(constants.casServerFrame);
    if(!cas_serverFrame)return;
    cas_serverFrame.src = frameURL;
    if(cas_serverFrame.attachEvent){
        cas_serverFrame.attachEvent('onload', function(){
            initEvents(e);
        });
    }else{
        cas_serverFrame.onload = function(){
            initEvents(e);
        }
    }
}

function registerListener(el, eventName, handle) {
    if (window.attachEvent) {
        el.attachEvent('on' + eventName, handle);
    } else if (window.addEventListener) {
        el.addEventListener(eventName, handle, false);
    }
}

function isKeyDownEnter(e) {
    e = e ? e : window.event;
    var _isie = (window.attachEvent) ? true : false;
    var _key = '';
    if (_isie) {
        _key = e.keyCode;
    } else {
        _key = e.which;
    }
    if (_key == 13)
        return true;
    else
        return false;
}

function getParam(name) {
    var queryString = window.location.search;
    var param = queryString.substr(1, queryString.length - 1).split("&");
    for (var i = 0; i < param.length; i++) {
        var keyValue = param[i].split("=");
        if (keyValue[0] == name) return keyValue[1];
    }
    return null;
}


四、为了实现验证成功后跳转到验证之前的URL资源,cas-server的验证成功后的redirect修改是必不可少了。

①修改WEB-INF/login-webflow.xml文件

搜索
修改为


②添加redirectView
打开WEB-INF\classes\default_views.properties
增加如下字段:
### 跳转回调页面
redirectView.(class)=org.springframework.web.servlet.view.JstlView
redirectView.url=/WEB-INF/view/jsp/default/ui/redirect.jsp


③新建/WEB-INF/view/jsp/default/ui/redirect.jsp
代码参考如下:

<%-- 
    Document   : redirect
    Created on : 2011-1-11, 17:42:09
    Author     : Kenny
--%>

<%@page contentType="text/html" pageEncoding="UTF-8"%>



    
        

        
    
    

    



附上本帖子提及过的文件和我测试的客户端项目,详细见附件。

题外:
本次开发是在netbeans上开发的,所以用eclipse的朋友导入demo项目可能要麻烦一些。不知道为何我的MyEclipse上的m4eclipse怎么没了,所以用不了maven插件,懒得弄就直接用netbeans了,因为NetBeans 6.9版本对maven支持很好。

参考:
http://fallenlord.blogbus.com/logs/36905130.html
http://fallenlord.blogbus.com/logs/36907990.html
http://fallenlord.blogbus.com/logs/36907044.html
  • CAS-Server_WEB-INF.rar (3.3 KB)
  • 下载次数: 393
  • sso_demo.rar (155.4 KB)
  • 下载次数: 474

你可能感兴趣的:(应用服务器,Netbeans,JSP,SSO,maven)