关键词:Grails CAS GWT GWT-EXT IntelliJ IDEA 单点登录 AJAX应用
最近在用Grails框架开发一个Web应用系统,需要与已有的异构Web系统实现单点登录的效果,同时为了增加程序的用户体验要用到AJAX技术,因此在系统中集成了CAS和GWT插件,并在GWT插件中加入了GWT-EXT库。本文的目的是给出各种配置细节,为有做同样开发兴趣的朋友提供一些借鉴,少走弯路提高效率。
一、Grails项目与CAS集成,实现单点登录功能。
开发环境:
OS:Windows XP
IDE:Intellij
IDEA 7.0
Web Framework: Grails 1.0.3
Web Server: Tomcat
6.0
DB server: MySQL
5.0
CAS: cas-server-3.2.1
、 cas-client-3.1.3
CAS是耶鲁大学的一个开源项目,提供企业应用的单点登录功能。CAS由一个Java实现的服务器端组件和支持众多平台的客户端插件库两大部分组成。其丰富的插件库涵盖了目前各个主要的Web开发平台。CAS通过一个公用的认证系统统一管理和验证用户的身份。在CAS上认证的用户将获得CAS颁发的一个数字证书,凭借这个证书,用户可以在承认CAS证书的各个系统上自由穿梭访问,不需要再次登录认证。要完成该认证过程,就需要一个认证中心服务器CAS Server和嵌入在不同Web应用系统的认证客户端CAS Client进行协同。 其运行原理如图1所示,用户通过Web浏览器向某个Web服务程序发出访问请求,该HTTP请求被安装在Web服务端的CAS客户端程序(HTTP过滤 器)拦截,客户端审查该请求是否带有CAS服务器下发的证书,如果没有则该请求被重定向到CAS服务器进行认证并发放证书,认证成功后,用户的请求才被引导到Web服务程序。
图1 CAS实现单点登录的基本原理
第一步,搭建Java Web服务器,用于部署CAS的中央认证服务
下载并安装JDK、Tomcat6.0,设置好环境变量JAVA_HOME以及CATALINA_HOME。如:JAVA_HOME = C:"Sun"SDK"jdk, CATALINA_HOME = D:"Program Files"Apache Software Foundation"Tomcat 6.0。访问http://localhost:8080,出现Tomcat的管理页面,则配置成功。
第二步,生成数字证书
在命令行窗口执行以下3条命令:
keytool -genkey -keyalg RSA -alias demo -dname "cn=demo.com" -storepass changeit,创建一个别名为demo的证书,使用RSA算法,证书的DN域为demo.com,在证书数据库里的存储密码为changeit。要注意的是在域名服务器里做好demo.com与CAS服务器IP的对应解析,如果不具备进行域名解析的条件,可以在DN域填写服务器的主机名。
keytool -export -alias demo -file %jAVA_HOME%/jre/lib/security/demo.crt -storepass changeit,从证书导出为证书文件demo.crt。
keytool -import -alias demo -file %JAVA_HOME%/jre/lib/security/demo.crt -keystore %JAVA_HOME%/jre/lib/security/cacerts -storepass changeit,将demo.crt导入jre的可信任证书仓库。
需要注意的是,Tomcat默认的JRE路径不一定跟你的JAVA_HOME一致(参照Tomcat->configure->java->Java Vritual Machine记录的路径),而CAS是按照Tomcat默认的位置去寻找证书,因此在这种情况下你应该加入这样两个命令以防万一:
keytool -export -alias demo -file “Tomcat默认的jre”/lib/security/demo.crt -storepass changeit
keytool -import -alias demo -file “Tomcat默认的jre”/lib/security/demo.crt -keystore “Tomcat默认的jre”/lib/security/cacerts -storepass changeit
第三步,配置Tomcat支持HTTPS
CAS的认证过程是基于安全的http数据传输的,因此需要开启HTTPS功能。编辑%CATALINA_HOME%/conf/server.xml,找到默认被注释的port="8443"那一行进行编辑,如下例:
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
enableLookups="true" disableUploadTimeout="true"
keystoreFile="C:"Documents and Settings"xin".keystore" keystorePass="changeit"
truststoreFile="C:"Program Files"Java"jre1.6.0"lib"security"cacerts"
clientAuth="false" sslProtocol="TLS" />
现在访问https://localhost:8443,如果浏览器弹出窗口,要求你接受证书,如图2,而你接受证书后出现Tomcat管理页,则证明证书制作和HTTPS配置都已成功,第三步完成。
图2 启用https并接受服务器下发的数字证书
第四步,在Tomcat上部署CAS中央认证服务器
以版本3.2.1为例,在cas-server-3.2.1/modules下,有一个打包好的War文件cas-server-webapp- 3.2.1.war,将其拷贝到%CATALINA_HOME%/webapp下并改名为cas.war,进行部署。访问网址http: //localhost:8080/cas/index.jsp,如果出现CAS的登录界面,如图3,则说明部署成功。
图3 部署CAS认证服务器
第五步,配置CAS使用JDBC数据源进行用户认证
CAS服务器默认的用户验证策略是只要用户名和密码相同就可以通过认证,过于简单,必须进行修改。我们以MySQL数据库中test库中的sso_user表作为数据源来进行验证。在MySQL数据库中,创建sso_user表,存放整个单点登录体系内通用的用户名和密码:
CREATE TABLE `sso_user` (
`username` varchar(30) NOT NULL default '',
`password` varchar(45) NOT NULL default '',
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
并添加用户:
INSERT INTO `sso_user` (`username`,`password`) VALUES
('test1','pass1'),
('test2','pass2');
然后编辑%CATALINA_HOME%/webapps/cas/WEB-INF/deployerConfigContext.xml,找到<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
注释掉该行,替换为:
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="sql" value="select password from sso_user where username=?" />
<property name="dataSource" ref="dataSource" />
</bean>
并添加一个bean:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://localhost:3306/test</value></property>
<property name="username"><value>test</value></property>
<property name="password"><value>test</value></property>
</bean>
拷贝cas-server-support-jdbc-3.2.1.jar和mysql-connector-java-5.1.6-bin.jar到%CATALINA_HOME%/webapps/cas/WEB-INF/lib下。
现在,CAS服务器端的配置都已完成,认证的工作由cas服务器来做,而如何将认证的任务安全转移到cas服务器,就是接下来的cas客户端的工作了。
第六步,配置CAS客户端,并与Grails项目集成
CAS客户端不是单独存在的,它以插件的形式嵌入到基于各种平台的Web应用程序中,目前主要的web平台,Java、.net、PHP、Python、Perl等等,都能得到很好的支持。在本文中我们以Grails平台为例来进行分析。
Grails是Java社区新出现的开源敏捷Web开发框架,配合使用与Java无缝集成的Groovy动态语言,Groovy和Grails就如同Ruby与Rails的关系。
用Grails进行项目开发,显然不适用只依靠命令行和文本编辑器来开发,在IDE的选择上,本人推荐Intellij IDEA 7.0,这是目前为止对Groovy和Grails特性支持最好的IDE,在这一方面要远胜于Eclipse。
在IDE上支持Grails特性:
IDEA的基本配置不支持Grails,需要安装一个JetGroovy插件。安装并运行IDEA,选择file->settings->Plugins,出现插件库对话框,如图4,选择Available标签页,在可用插件列表中选择安装JetGroovy插件就OK了。
图4 在IntelliJ IDEA 7.0上安装JetGroovy插件
建立项目:
新的Grails项目,可以在IDEA里直接新建Grails Application,也可以在Grails的CLI环境里,运行grails create-app创建项目,然后再用IDEA导入项目文件。Grails项目的目录结构如图5:
图5 Grails程序的文件目录
更改Web服务端口:
Grails内置了一个Web服务器Jetty,默认端口是8080,这与Tomcat的默认端口是一样的,如果你的开发环境中8080已经被占用了,那么就需要更改Grails的服务端口,方法如下:
在$GRAILS_HOME/scripts/Init.groovy 中找出以 serverPort 开头的那一行,并更改值:
serverPort = System.getProperty('server.port') ?
System.getProperty('server.port').toInteger() : 9090
安装cas-plugin:
打开Grails命令行工具,改变当前路径到项目根目录,运行Grails install-plugin cas-client,
Grails会在项目根目录/plugins下添加gwt相关资源。同时,在IDEA中我们也需要提醒IDE安装了插件,打开项目工程的Mudule Settings,在设置页的最左边一栏选择Libraries,然后在中间一栏右键选择New Project Library,在弹出窗口中填写CAS-Plugin,如图6所示:
图6 建立CAS-Plugin的依赖库
接下来在最后边一栏点击Attach Jar Directories,指明CAS客户端库文件的路径,即项目根目录/plugins/cas-client-1.0"lib,好准备工作完成。
假如我们的Grails Application名字是test,那么运行程序,然后在浏览器输入http://localhost:9090/test,就能出现欢迎Grails的欢迎页面。
将认证工作交给CAS服务器:
编辑$项目主目录$/grails-app/conf下的Config.groovy文件,加入以下代码:
// cas client configuration, required by CasClientPlugin
cas {
urlPattern = '/*'
// urlPattern = ['/oneurl/*', '/another', '/anotheranother/*']
disabled = false
}
environments {
development {
cas.loginUrl = 'https://demo.com:8443/cas/login'
cas.validateUrl = 'https://demo.com:8443/cas/serviceValidate'
cas.serverName = 'localhost:9090'
// cas.serviceUrl = 'http://dev.casclient.demo.com/access'
cas.disabled = false
cas.mocking = true
}
test {
// cas.loginUrl = 'https://test.casserver.demo.com/cas/login'
// cas.validateUrl = 'https://test.cas.com/cas/serviceValidate'
// cas.serverName = 'test.casclient.demo.com:80'
// cas.serviceUrl = 'http://test.casclient.demo.com/access'
}
production {
// cas.loginUrl = 'https://prod.casserver.demo.com/cas/login'
// cas.validateUrl = 'https://prod.casserver.demo.com/cas/serviceValidate'
// cas.serverName = 'prod.casclient.demo.com:80'
// cas.serviceUrl = 'http://prod.casclient.demo.com/access'
}
}
起关键作用的就是加亮显示的3行代码,当用户访问http://localhost:9090/test时,请求会被重定向到https://demo.com:8443/cas/login.jsp进行登录,然后由https://demo.com:8443/cas/serviceValidate.jsp进行身份验证,通过后,请求才回到初始目的地址。
至此,我们就完成了CAS的集成。