安装环境
- Tomcat7.0
- JDK6
- CAS SERVER 3.5.1,下载地址 http://www.jasig.org/cas/download
- CAS CLIENT 3.2.1,下载地址 http://downloads.jasig.org/cas-clients/?C=M;O=D
常用命令
创建证书
证书是单点登录认证系统中很重要的一把钥匙,客户端于服务器的交互安全靠的就是证书,这里使用JDK自带的keytools工具生成证书,
如果以后真正在产品环境中使用肯定要去证书提供商去购买。
用JDK自带的keytool工具生成证书:
keytool -genkey -alias cas -keyalg RSA -keystore f:/resources/cas
输入完信息之后,输入 y,然后输入密码,提交。
C:\Windows\System32\drivers\etc\hosts
添加内容如下:
127.0.0.1 sso.rying.com
这样在访问sso.rying.com的时候其实是访问的127.0.0.1也就是本机
导出证书
F:\resources>keytool -export -file f:/resources/cas.crt -alias wsria -keystore f:/resources/cas
输入密码,提交。
客户端JVM导入证书
keytool -import -keystore E:\develop\Java\jdk1.6.0_37\jre\lib\security\cacerts -file f:\resources\cas.crt -alias cas
至此证书的创建、导出、导入到客户端JVM都已完成
应用到tomcat
<!-- Define a SSL HTTP/1.1 Connector on port 8443
This connector uses the JSSE configuration, when using APR, the
connector should be using the OpenSSL style configuration
described in the APR documentation -->
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" keystoreFile="F:/resources/cas" keystorePass="root123" />
但是修改之后,发现tomcat启动报错:
严重: Failed to initialize end point associated with ProtocolHandler ["http-apr-8443"]
java.lang.Exception: Connector attribute SSLCertificateFile must be defined when using SSL with APR
at org.apache.tomcat.util.net.AprEndpoint.bind(AprEndpoint.java:494)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:610)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:429)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:981)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
at org.apache.catalina.core.StandardService.initInternal(StandardService.java:559)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:814)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
at org.apache.catalina.startup.Catalina.load(Catalina.java:633)
at org.apache.catalina.startup.Catalina.load(Catalina.java:658)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:281)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:450)
2013-2-19 10:30:25 org.apache.catalina.core.StandardService initInternal
严重: Failed to initialize connector [Connector[HTTP/1.1-8443]]
org.apache.catalina.LifecycleException: Failed to initialize component [Connector[HTTP/1.1-8443]]
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:106)
at org.apache.catalina.core.StandardService.initInternal(StandardService.java:559)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:814)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
at org.apache.catalina.startup.Catalina.load(Catalina.java:633)
at org.apache.catalina.startup.Catalina.load(Catalina.java:658)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.load(Bootstrap.java:281)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:450)
Caused by: org.apache.catalina.LifecycleException: Protocol handler initialization failed
at org.apache.catalina.connector.Connector.initInternal(Connector.java:983)
at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
... 12 more
Caused by: java.lang.Exception: Connector attribute SSLCertificateFile must be defined when using SSL with APR
at org.apache.tomcat.util.net.AprEndpoint.bind(AprEndpoint.java:494)
at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:610)
at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:429)
at org.apache.catalina.connector.Connector.initInternal(Connector.java:981)
... 13 more
<Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" keystoreFile="F:/resources/cas" keystorePass="root123" />
CAS服务器配置
CAS链接数据源登入配置
上面的初体验仅仅是简单的身份验证,实际应用中肯定是要读取数据库的数据,下面我们来进一步配置CAS服务器怎么读取数据库的信息进行身份验证。首先打开
tomcat/webapp/cas/WEB-INF/deployerConfigContext.xml
找到<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
把这个简单登入验证注释掉,修改
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="dataSource" ref="dataSource"></property>
<property name="sql" value="select password from user where username=?"></property>
</bean>
最后在配置文件末尾前加上
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/test?autoReconnect=true&useUnicode=true&characterEncoding=utf-8</value>
</property>
<property name="username"><value>root</value></property>
<property name="password"><value>root</value></property>
<property name="defaultAutoCommit"><value>false</value></property>
</bean>
表:
-- ----------------------------
-- Table structure for `user`
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ('1', 'irwin', '123');
INSERT INTO `user` VALUES ('2', 'janey', '456');
INSERT INTO `user` VALUES ('3', 'harris', '789');
INSERT INTO `user` VALUES ('4', 'howard', '110');
INSERT INTO `user` VALUES ('5', 'morris', '888');
INSERT INTO `user` VALUES ('6', 'stephen', '999');
INSERT INTO `user` VALUES ('7', 'linsay', '000');
INSERT INTO `user` VALUES ('8', 'lilian', '111');
INSERT INTO `user` VALUES ('9', 'perry', '666');
INSERT INTO `user` VALUES ('10', 'laura', 'eeee');
INSERT INTO `user` VALUES ('20', 'www', 'ddd');
INSERT INTO `user` VALUES ('21', 'dd', 'dd');
赋值 F:\resources\cas-server-3.5.1\modules\cas-server-support-jdbc-3.5.1.jar 到 tomcat/webapp/cas/WEB-INF/lib目录
这里由于我使用的DBCP数据源,需要加入相应的jar包,如果使用其他数据源,加入相应的jar包即可。
使用现在数据库存在的数据登入成功:
QueryDatabaseAuthenticationHandler:cas-server-support-jdbc提供的查询接口其中一个,QueryDatabaseAuthenticationHandler是通过配置一个 SQL 语句查出密码,与所给密码匹配。
如果需要使用密码加密,可以创建一个类继承 org.jasig.cas.authentication.handler.PasswordEncoder,然后在encode中加密用户输入的密码返回即可。
如果需要在代码中获取用户名密码进行验证,可以创建一个类继承 org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler,重写
authenticateUsernamePasswordInternal方法。
CAS客户端配置
<!-- 登出 -->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!-- 登出 ,改filter要在其他filter之前-->
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<!-- 用於单点登录拦截验证 -->
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://sso.rying.com:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
</filter>
<!-- 请求参数ticket验证(ticket即子系统与CAS系统进行交互的凭证) -->
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://sso.rying.com:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
</filter>
<!--
该过滤器负责实现HttpServletRequest请求的包裹,
比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。
-->
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<!--
该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
比如AssertionHolder.getAssertion().getPrincipal().getName()。
-->
<filter>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
启动服务器,浏览器访问 http://localhost:8080/CASClient/hello.html
界面美化
- 登入页面:casLoginView.jsp
- 登入成功页面:casGenericSuccess.jsp
- 登出页面:casLogoutView.jsp