本次配置CAS耗时1周有余,从中学到了很多东西,现将这些东西整理一下分享出来,以供后来者借鉴。
起初接到这个任务,我就开始在网上搜资料,各种帖子来看,但是效果并不是很理想,因为帖子太多了,说法太多了,而且都不是很符合自己的实际项目情况。
其中关于配置这一块我不得不提一下这个帖子,http://www.kafeitu.me/sso/2010/11/05/sso-cas-full-course.html
说得很详细,也很全面,只要不是太粗心,都能够一次通过cas的配置。
?
首先,这个帖子是在你对CAS有一定的了解了之后才能看懂。
大致说一下,我的项目环境,分为两个子项目,一个是php,一个是java。
PHP需要下载phpCas,https://wiki.jasig.org/display/CASC/phpCAS
java需要下载cas-client,https://wiki.jasig.org/display/CASC/CAS+Client+for+Java+3.1,
至于配置的细节,官网比我所见到的帖子都更加详尽,所以可以参考官网https://wiki.jasig.org。
TGT:ticket granting ticket 在用户在CAS认证成功后,CAS生成cookie,写入浏览器,同时生成一个TGT对象,放入自己的缓存,TGT对象的ID就是cookie的值。当HTTP再次请求到来时,如果传过来的有CAS生成的cookie,则CAS以此cookie值为key查询缓存中有无TGT ,如果有的话,则说明用户之前登录过,如果没有,则用户需要重新登录。
ST:service ticket?ST是CAS为用户签发的访问某一service的票据。用户访问service时,service发现用户没有ST,则要求用户去CAS获取ST。用户向CAS发出获取ST的请求,如果用户的请求中包含cookie,则CAS会以此cookie值为key查询缓存中有无TGT,如果存在TGT,则用此TGT签发一个ST,返回给用户。用户凭借ST去访问service,service拿ST去CAS验证,验证通过后,允许用户访问资源。
ST的使用次数(默认一次)和过期时间,TGT的过期时间在cas\WEB-INF\spring-configuration\ticketExpirationPolicies.xml里面设置。
下面是我在本次配置的过程中出现的问题及其解决方法:
1.在配置php客户端的时候,Fatal error: Call to undefined function curl_init() in D:\MYOA\webroot\CAS\Request\CurlRequest.php on line 105
解决办法:添加php_curl模块,打开php.ini的注释,然后下载相应版本的php_curl.dll及其依赖的动态链接库ssleay32.dll和libeay32.dll。
2.去掉https的认证协议,使用http协议进行认证和ticket的传输
解决方法:在cas\WEB-INF\deployConfig.xml里面将
monospace !important; border: 0px !important; background-image: none !important; text-align: right !important; float: none !important; vertical-align: baseline !important; height: auto !important; width: 2.7em !important; line-height: 1.1em !important; font-size: 10pt !important; display: block !important;">1
class="plain"><
bean
?class
=
"org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
2
p:httpClient-ref
=
"httpClient"
/>
添加一个属性
1
<
bean
?class
=
"org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
2
p:httpClient-ref
=
"httpClient"
?p:requireSecure
=
"false"
/>
?
?
还有一个地方,cas\WEB-INF\spring-configuration\ticketGrantingTicketCookieGenerator.xml
修改成,
1
<
bean
?id
=
"ticketGrantingTicketCookieGenerator"
?class
=
"org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
2
????????
p:cookieSecure
=
"false"
//使用http进行cookie传输
3
????????
p:cookieMaxAge
=
"3600"
4
????????
p:cookieName
=
"CASTGC"
5
????????
p:cookiePath
=
"/cas"
?/>
?
?
另外,web.xml里面的casServerLoginUrl需要修改成http协议
?
3.在cas中使用jasypt查看认证的用户名密码是否正确
解决方法:在deployConfig.xml里面修改默认的认证方法(默认的认证方式是,用户名密码相同即通过认证),
1
<
bean
?class
=
"org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"
>
2
????????????????????
<
property
?name
=
"dataSource"
?ref
=
"casDataSource"
?/>
3
????????????????????
<
property
?name
=
"sql"
?value
=
"select SYS_USER.SU_PASSWORD from SYS_USER where lower(SYS_USER.SU_NICKNAME_CODE)=lower(?)"
?/>?
4
????????????????
</
bean
>
使用上面这一段替换SimpleTestUsernamePasswordAuthenticationHandler,然后在配置文件中加入下面的数据源即可。
?
?
01
<
bean
?id
=
"casDataSource"
?class
=
"org.apache.commons.dbcp.BasicDataSource"
>
02
????????
<
property
?name
=
"driverClassName"
>
03
??????????
<
value
>oracle.jdbc.driver.OracleDriver</
value
>
04
????????
</
property
>
05
????????
<
property
?name
=
"url"
>
06
??????????
<
value
>jdbc:oracle:thin:@192.168.0.141:1521:xe</
value
>
07
????????
</
property
>
08
????????
<
property
?name
=
"username"
>
09
??????????
<
value
>em_mip</
value
>
10
????????
</
property
>
11
????????
<
property
?name
=
"password"
>
12
??????????
<
value
>mip00</
value
>
13
????????
</
property
>
14
???
</
bean
>
?
?
然后,下载cas-server-support-jdbc.jar的源码,进行修改,下载链接http://grepcode.com/snapshot/repo1.maven.org/maven2/org.jasig.cas/cas-server-support-jdbc/3.3.5
解压,导入到eclipse,修改QueryDatabaseAuthenticationHandler,修改后的代码如下:
01
/*
02
?
* Copyright 2007 The JA-SIG Collaborative. All rights reserved. See license
03
?
* distributed with this file and available online at
04
?
* http://www.ja-sig.org/products/cas/overview/license/
05
?
*/
06
package org.jasig.cas.adaptors.jdbc;
07
?
08
import org.jasig.cas.authentication.handler.AuthenticationException;
09
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
10
import org.jasypt.util.password.BasicPasswordEncryptor;
11
import org.springframework.dao.IncorrectResultSizeDataAccessException;
12
?
13
/**
14
?
* Class that if provided a query that returns a password (parameter of query
15
?
* must be username) will compare that password to a translated version of the
16
?
* password provided by the user. If they match, then authentication succeeds.
17
?
* Default password translator is plaintext translator.
18
?
*
19
?
* @author Scott Battaglia
20
?
* @author Dmitriy Kopylenko
21
?
* @version $Revision: 42776 $ $Date: 2008-01-04 09:15:42 -0500 (Fri, 04 Jan 2008) $
22
?
* @since 3.0
23
?
*/
24
public final class QueryDatabaseAuthenticationHandler extends
25
????
AbstractJdbcUsernamePasswordAuthenticationHandler {
26
?
27
????
private String sql;
28
?
29
????
protected final boolean authenticateUsernamePasswordInternal(
30
????????
final UsernamePasswordCredentials credentials)
31
????????
throws AuthenticationException {
32
????????
final String username = credentials.getUsername();
33
????????
final String password = credentials.getPassword();
34
????????
try {
35
????????????
final String dbPassword = getJdbcTemplate().queryForObject(
36
????????????????
this.sql, String.class, username);
37
????????????
return new BasicPasswordEncryptor().checkPassword(password, dbPassword);//主要是修改了这里
38
????????
} catch (final IncorrectResultSizeDataAccessException e) {
39
????????????
// this means the username was not found.
40
????????????
return false;
41
????????
}
42
????
}
43
?
44
????
/**
45
?????
* @param sql The sql to set.
46
?????
*/
47
????
public
?void
?setSql(
final
?String sql) {
48
????????
this
.sql = sql;
49
????
}
50
}
?
?
然后,把各种依赖包导到build path里面去,让项目不报错。
打成jar包,放到cas server 的lib目录下面去即可。
?
4.修改登录界面和登录成功的界面
解决方法:cas\WEB-INF\view\jsp\default\ui
更改:casLoginView.jsp和casGenericSuccess.jsp
登录界面需要自己去套,form表单里面有些东西是不能更改的,否则会出现不能认证的情况。值得一提的是页面的外部css或者图片是放在cas\css和cas\images下面的。贴上我的页面以供大家参考:
01
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
02
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
03
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
04
<%@ page contentType="text/html; charset=UTF-8" %>
05
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
06
<
html
?xmlns
=
"http://www.w3.org/1999/xhtml"
>
07
<
head
>
08
<
meta
?http-equiv
=
"Content-Type"
?content
=
"text/html; charset=UTF-8"
?/>
09
<
title
>EIP登录页面</
title
>
10
<
style
?type
=
"text/css"
>
11
????
* { padding:0; margin:0;}
12
????
.eip-login{ width: 950px; height:700px; margin:auto;background:url(images/eip_login_bg.jpg) no-repeat;}
13
????
.eip-login-form { padding-left:684px;padding-top:353px;}
14
????
.eip-login-form input { border:0 none;}
15
????
.eip-login-box p { position: relative;margin-top: 10px;*margin-top:7px;margin-left: 30px;}
16
????
.eip-position-box { height:28px;line-height: 28px;width: 170px;color:gray; position:absolute;z-index:88;top:0;left:0px;font-size: 12px;display: inline-block;padding-left: 10px;cursor: text;}
17
????
.eip-username, .eip-password{ height: 22px; padding: 3px; line-height: 22px; width:170px;background:#f3f3f3;padding-left: 10px;}
18
????
.eip-submit { width:229px;height:47px;background:url(images/eip_login.png) no-repeat;margin-top: 15px;cursor: pointer;}
19
????
.eip-reset { margin-left:180px;cursor:pointer;background:#fff;}
20
</
style
>
21
<
script
?type
=
"text/javascript"
?src
=
"js/jquery-1.72.js"
></
script
>
22
<
script
?type
=
"text/javascript"
>
23
$(function(){
24
????
$(".eip-username").focus(function(){
25
????????
var username = $(".eip-username").val();
26
????????
if( username == '请填写EIP系统帐号(或花名)'){
27
????????????
$(this).val('');
28
????????
}
29
????
});
30
????
$(".eip-username").blur(function(){
31
????????
var username = $(".eip-username").val();
32
????????
if( username == ' '){
33
????????????
$(this).val('请填写EIP系统帐号(或花名)');
34
????????
}
35
????
});
36
????
$(".eip-reset").click(function(){
37
????????
$("#editForm").reset();
38
????
});
39
});
40
</
script
>
41
</
head
>
42
?
43
<
body
>
44
????
?
45
????????
<
form:form
?method
=
"post"
?commandName
=
"${commandName}"
?htmlEscape
=
"true"
?id
=
"edit-form"
>
46
????????????
<
div
?class
=
"eip-login"
>
47
????????????????
<
div
?class
=
"eip-login-form"
>
48
????????????????????
<
div
?class
=
"eip-login-box"
>
49
????????????????????
<
p
>
50
????????????????????????
<
c:if
?test
=
"${not empty sessionScope.openIdLocalId}"
>
51
????????????????????????????
<
strong
>${sessionScope.openIdLocalId}</
strong
>
52
????????????????????????????
<
input
?type
=
"hidden"
?id
=
"username"
?name
=
"username"
?value
=
"${sessionScope.openIdLocalId}"
?/>
53
????????????????????????
</
c:if
>
54
????????????????????????
<
c:if
?test
=
"${empty sessionScope.openIdLocalId}"
>
55
????????????????????????????
<
form:input
?class
=
"eip-username"
??cssErrorClass
=
"error"
?id
=
"username"
?value
=
"请填写EIP系统帐号(或花名)"
?size
=
"25"
?tabindex
=
"1"
?accesskey
=
"${userNameAccessKey}"
?path
=
"username"
?autocomplete
=
"false"
?htmlEscape
=
"true"
?/>
56
????????????????????????
</
c:if
>
57
????????????????????
</
p
>
58
????????????????????
<
p
>
59
????????????????????????
<
form:password
?class
=
"eip-password"
?cssErrorClass
=
"error"
?id
=
"password"
?size
=
"25"
?tabindex
=
"2"
?path
=
"password"
??accesskey
=
"${passwordAccessKey}"
?htmlEscape
=
"true"
?autocomplete
=
"off"
?/>
60
????????????????????
</
p
>
61
????????????????????????
<
input
?type
=
"hidden"
?name
=
"lt"
?value
=
"${flowExecutionKey}"
?/>
62
????????????????????????
<
input
?type
=
"hidden"
?name
=
"_eventId"
?value
=
"submit"
?/>
63
?
64
????????????????????????
<
div
><
input
?class
=
"eip-submit"
?name
=
"submit"
?accesskey
=
"l"
?value
=
""
?tabindex
=
"4"
?type
=
"submit"
?/></
div
>
65
????????????????????????
<
div
><
input
?class
=
"eip-reset"
?name
=
"reset"
?accesskey
=
"c"
?value
=
"重置"
?tabindex
=
"5"
?type
=
"reset"
?/></
div
>
66
????????????????????
</
div
>
67
????????????????
</
div
>
68
????????????
</
div
>
69
????????
</
form:form
>
70
</
body
>
71
</
html
>
?
?
?
回头一看,其实整个配置也没多难,可是其中的过程却是曲折离奇。
如果大家有什么疑问可以留言,能够帮助解决的我会尽量解答的。