简介
CAS项目官网 是一款开源的单点登录解决方案,可以直接再Tomcat,Jetty等WEB容器上运行,支持多种开发语言
下载
下载cas-server-XXX-release.zip(地址)
注意:官网提供的所有版本中,最新的版本(4.0以上)可能没有release.zip包
修改tomcat
创建秘钥
生成keypair
在 $JRE_HOME/bin/
目录下创建命令行,输入以下命令,其中CN
的值必须保持和主机名一致,假设密码为 mypass
,再继续填写信息,遇到主密码直接回车
keytool -genkeypair -alias cas -keyalg RSA -storepass mypass
上述命令会在用户目录下生成一个.keystore文件,后面会使用该文件其他的几个常用命令
# 查看 keypair:
keytool -list -storepass mypass
# 删除 keypair:keytool -delete -alias <别名> -storepass mypass
导出证书
keytool -exportcert -alias cas -file cas.crt -storepass mypass
上述命令会在当前目录生成一个cas.crt证书文件,后面也会使用该文件
向JVM导入证书
keytool -importcert -alias cas -file cas.crt -keystore "%JAVA_HOME%\jre\lib\security\cacerts" -storepass mypass -noprompt
上面的JAVA_HOME
需要换成实际的路径
配置tomcat
修改配置文件
不同版本的cas对jdk版本的要求不一样,请查阅cas说明
修改tomcat目录下的conf/server.xml,打开SSL
<Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="off" />
配置HTTPS端口
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11Protocol"
SSLEnabled="true"
maxThreads="150"
scheme="https"
secure="true"
clientAuth="false"
sslProtocol="TLS"
keystoreFile="apache-tomcat-7.0.73\conf\security\.keystore"
keystorePass="mypass"/>
如果要确保访问HTTPS服务只能用8443端口,则需要禁用其他端口号
访问cas服务
重启tomcat: 在 tomcat/bin/
下先执行 shutdown
,再执行 startup
。访问cas的地址为 https://localhost:8443/cas/login
WEB集成CAS-CLIENT
在Spring服务的pom.xml
加入cas-client的依赖包
<!--cas client-->
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.3.3</version>
</dependency>
在Spring的项目配置文件web.xml
中加入cas的配置
<!-- ======================== 单点登录开始 ======================== -->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!-- 该过滤器用于实现单点登出功能,可选配置。 -->
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>CAS Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://nkgy4l003835331:8443/cas/login</param-value>
<!-- 这里只能使用主机名的url -->
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
<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://nkgy4l003835331:8443/cas</param-value>
<!-- 这里只能使用主机名的url -->
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8080</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
该过滤器负责实现HttpServletRequest请求的包裹,
比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。
-->
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>
org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
该过滤器使得开发者可以通过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 Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ======================== 单点登录结束 ======================== -->
同一个Tomcat下部署CAS-Server和Spring Web需要在tomcat的server.xml
中创建两个Service
<!-- 用于HTTP应用 -->
<Service name="Catalina">
</Service>
<!-- 用于CAS的HTTPS应用 -->
<Service name="Catalina.cas">
</Service>
将HTTPS的移动到Catalina.cas中,并配置context的path路径cas的包路径
<Service name="Catalina.cas">
<Connector port="8443"
protocol="org.apache.coyote.http11.Http11Protocol" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="F:\software\apache-tomcat-7.0.73-windows-x64\apache-tomcat-7.0.73\conf\security\keystore.jks"
keystorePass="changeit"/>
<Engine name="Catalina.cas" defaultHost="localhost">
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="false" deployOnStartup="false">
<Context path="/cas" docBase="cas" reloadable="false" />
配置HTTP的context
与上一步类似,context的path填WEB项目的地址
CAS连接数据库
复制cas下载包中的 cas-server-support-jdbc-*.jar
到 tomcat/webapps/cas/WEB-INF/lib
中
复制数据库驱动包(如 mysql-connector.jar
)到 tomcat/webapps/cas/WEB-INF/lib
中
- 修改cas配置文件: 在
tomcat/webapps/cas/WEB-INF/cas.properties
中加入以下数据库的配置
# == Basic database connection pool configuration ==
database.driverClass=com.mysql.jdbc.Driver
database.url=jdbc:mysql://127.0.0.1:3306/test
database.user=root
database.password=root
修改 tomcat/webapps/cas/WEB-INF/deployerConfigContext.xml 配置
- 注册dataSource的bean
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" p:driverClassName="${database.driverClass}" p:url="${database.url}" p:username="${database.user}" p:password="${database.password}"> </bean>
- 注册密码加密的bean,这里的bean的实现类可以是自定义的加密类,只要实现encode方法就可以
// 以下使用cas自带的加密类 <bean id="md5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"> <constructor-arg index="0"> <value>MD5</value> </constructor-arg> </bean>
- 注释默认的校验规则bean,默认判断用户名和密码相等即可
<!-- <bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" /> -->
- 在上述注释后面添加新的校验bean,注意sql的值要完全和设计的登陆表对应
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> <property name="dataSource" ref="dataSource"></property> <property name="sql" value="select password from tb_user where account=?"></property> <property name="passwordEncoder" ref="md5PasswordEncoder"></property> </bean>
重启tomcat重新登陆
CAS自定义登陆页面
CAS的登陆页jsp文件在 tomcat/webapps/cas/WEB-INF/view/jsp/default/ui/casLoginView.jsp
修改注意事项
- 可以自由定义样式和脚本
- 要引入静态资源,需要将被引入的文件放在
tomcat/webapps/cas
目录下的位置,可以参考tomcat/webapps/cas/css
,引用代码示例:
<link href="/css/login.css" rel="stylesheet" type="text/css">
保持以下内容完整,因为以下内容会将值传给login请求
<form:form method="post" id="fm1" cssClass="fm-v clearfix" commandName="${commandName}" htmlEscape="true">
<input type="hidden" name="lt" value="${loginTicket}" />
<input type="hidden" name="execution" value="${flowExecutionKey}" />
<input type="hidden" name="_eventId" value="submit" />
<form:input id="username" .../>
<form:password id="password" .../>
原有的控件具有友好的功能,可以适当考虑保留和优化,如下面是登陆失败提示凭证错误的控件
<form:errors path="*" id="msg" cssClass="errors" element="div" />
保存文件,刷新浏览器即可
CAS加入注册功能(扩展:其他任意功能)
在CAS Server上添加注册功能
CAS本身不具有注册功能,因为CAS要开放注册业务给其他业务系统,CAS单一负责登陆校验和会话管理
修改步骤
在 tomcat/webapps/cas/WEB-INF/view/jsp/default/ui/
中加入注册页的jsp文件,如casRegisterView.jsp
,传入参数为username
和password
在 tomcat/webapps/cas/WEB_INF/classes/default_views.properties
中添加注册页的view映射
添加注册页
casRegisterView.(class)=org.springframework.web.servlet.view.JstlView
casRegisterView.url=/WEB-INF/view/jsp/default/ui/casRegisterView.jsp
- 创建注册控制类RegisterController.java,输入以下代码
package x.y.z;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
//必须继承AbstractController控制器基础类
public class RegisterController extends AbstractController
{
private DatabaseHandler dataHandler;//数据库处理类(bean注入)
// 必须实现的方法
protected ModelAndView handleRequestInternal(HttpServletRequest request,
HttpServletResponse response) throws Exception
{
ModelAndView signinView=new ModelAndView();
String username=request.getParameter("username");
String password=request.getParameter("password");
if(username == null || username.equals("") || password == null || password.equals("")){
return new ModelAndView("casRegisterView");
}
boolean success = this.dataHandler.insertUser(username,password);
String viewName=getSignInView(request);
signinView.setViewName(viewName);
return signinView;
}
// 处理跳转url
protected String getSignInView(HttpServletRequest request) {
String service = ServletRequestUtils.getStringParameter(request, "service", "");
return ("redirect:login" + (service.length() > 0 ? "?service=" + service : ""));
}
// 开放设置dataHandler,用于bean注入
public void setDataHandler(DatabaseHandler handler){
this.dataHandler = handler;
}
}
- 创建数据库实现类DatabaseHandler.java,输入以下代码
package x.y.z;
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
import javax.sql.DataSource;
class DatabaseHandler{
// 数据库操作模板类
private SimpleJdbcTemplate jdbcTemplate;
// 数据源
private DataSource dataSource;
// 自定义方法,示例为插入一个新用户
public boolean insertUser(String username,String password){
int r = 0;
try {
r = this.jdbcTemplate.update("insert into tb_user(account,password,time) values(?,?,?)",username,password,System.currentTimeMillis()/1000);
}catch (Exception e){
e.printStackTrace();
return false;
}
return r > 0;
}
//设置datasource注入
public final void setDataSource(final DataSource dataSource) {
this.jdbcTemplate = new SimpleJdbcTemplate(dataSource);
this.dataSource = dataSource;
}
}
将3-4的两个java文件打包成jar文件,并最终放到
tomcat/webapps/cas/WEB-INF/lib
中- 第一步: 编译java文件
# 由于java文件中引用了其他类,所以需要用 -cp 链接jar包 javac -cp "tomcat/webapps/cas/WEB-INF/lib/*" RegisterController.java.java javac -cp "tomcat/webapps/cas/WEB-INF/lib/*" DatabaseHandler.java.java
- 第二步: 打包成jar包
# 可以将两个文件打包在一起,也可以分开打包。例如打包在一起,名字取为my-register.jar # @注意: 由于3-4创建的java文件包含package 值,所以用jar打包时必须将class文件放在当前目录下的package子目录下,例如当前目录下的 x/y/z/目录下 jar cvf my-register.jar x/y/z/*.class
修改
tomcat/webapps/cas/WEB-INF/cas-servlet.xml
文件配置- 注册dataHandler的bean
<bean id="dataHandler" class="com.cas.luodong.web.DatabaseHandler"> <property name="dataSource" ref="dataSource"></property> </bean>
- 注册registerController的bean
<bean id="registerController" class="com.cas.luodong.web.RegisterController" p:dataHandler-ref="dataHandler"/>
- 在 <bean id=”handlerMappingC” 的props中加入以下内容
<prop key="/register">registerController</prop> 修改 tomcat/webapps/cas/WEB-INF/web.xml 文件配置
- 加入servlet-mapping项
<servlet-mapping> <servlet-name>cas</servlet-name> <url-pattern>/validate</url-pattern> </servlet-mapping>
重启tomcat,访问 cas/register
可以看到结果
FQA
java.lang.IllegalArgumentException: casServerUrlPrefix cannot be null
解决办法: cas-client-core的版本3.4.1不支持RC5,改为3.3.3即可
java.security.cert.CertificateException: No name matching localhost found
解决办法: jdk生成证书时填写的CN值必须为当前主机的主机名
java.security.cert.CertificateException: No subject alternative names present
解决办法: web.xml中的 casServerLoginUrl 和 casServerUrlPrefix 不能使用ip,必须使用CN值
CAS is Unavailable ; There was an error trying to complete your request. Please notify your support desk or try again.
解决办法: 检查ui下的jsp文件是否有误,确认标签匹配正确