Skip to content

CAS单点登录模块

Zhang Baofeng edited this page Jun 11, 2013 · 1 revision

使用情况

使用CAS来做统一的用户管理,和用户登录、身份验证相关的操作全部跳转到CAS让它来完成。单点登录是为了子系统们在用户管理方面的无缝衔接。我在自己机器上让CAS Server和solr Server共用了一个tomcat,端口在9080。CAS Client包导入web项目,并在web.xml里进行必要的filter和配置。在验证方面,我的jsp会从跳转回的结果里获取session里的信息,查看是否有登录了的用户,以此借助cas打通jsp和mysql数据库里的内容。

Server配置

在deployerConfigContext.xml里配置了我的验证方式,读取我指定的mysql里的某table,并做一次查询。

<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
    <property name="dataSource" ref="dataSource"></property>
    <property name="sql" value="select password from UserInfo where username=?"></property>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
   <property name="url"><value>jdbc:mysql://localhost:3307/academic</value></property>
   <property name="username"><value>root</value></property>
   <property name="password"><value></value></property>
</bean>

Server端的一些jsp的定制就不介绍了,我没有对其进行页面的改写定制。在这个xml里,我还定制了需要cas额外获取并写在session里的一些信息,

<bean id="attributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao">
	<constructor-arg index="0" ref="dataSource"/>
	<constructor-arg index="1" value="select * from UserInfo where {0}"/>
	<property name="queryAttributeMapping">
		<map>
			<entry key="username" value="username" />
		</map>
	</property>
	<property name="resultAttributeMapping">
		<map>
			<entry key="username" value="username"/>
			<entry key="name" value="name"/>
			<entry key="email" value="email"/>
			<entry key="weibo_url" value="weibo_url"/>
			<entry key="github_url" value="github_url"/>
			<entry key="interests" value="interests"/>
			<entry key="homepage" value="homepage"/>
		</map>
	</property>
</bean>

这部分session内的信息会存在一个特点的位置,下面会说明在jsp里怎么读取获取这些内容。

Client配置

配置信息都在web.xml下,

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>AcademicSearchEngine</display-name>
	<welcome-file-list>
		<welcome-file>about.jsp</welcome-file>
	</welcome-file-list>

	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
	</filter>

	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置 -->
	<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>
		<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>http://localhost:8443/cas/login</param-value>
		</init-param>
		<init-param>
			<!--这里的server是服务端的IP -->
			<param-name>serverName</param-name>
			<param-value>http://localhost:8080</param-value>
		</init-param>
		<init-param>
			<param-name>renew</param-name>
			<param-value>false</param-value>
		</init-param>
		<init-param>
			<param-name>gateway</param-name>
			<param-value>false</param-value>
		</init-param>
	</filter>

	<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>http://localhost:8443/cas</param-value>
		</init-param>
		<init-param>
			<param-name>serverName</param-name>
			<param-value>http://localhost:8080</param-value>
		</init-param>
		<init-param>
			<param-name>useSession</param-name>
			<param-value>true</param-value>
		</init-param>
		<init-param>
			<param-name>redirectAfterValidation</param-name>
			<param-value>true</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>
		<display-name>AutoSetUserAdapterFilter</display-name>
		<filter-name>AutoSetUserAdapterFilter</filter-name>
		<filter-class>dcd.academic.cas.AutoSetUserAdapterFilter</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>/home.jsp</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>CAS Validation Filter</filter-name>
		<url-pattern>/home.jsp</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
		<url-pattern>/home.jsp</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>CAS Assertion Thread Local Filter</filter-name>
		<url-pattern>/home.jsp</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>AutoSetUserAdapterFilter</filter-name>
		<url-pattern>/home.jsp</url-pattern>
	</filter-mapping>
</web-app>

在这个配置里,要注意一些端口、域名之类的名称,不然会造成各种失败的。可以看到我的过滤对象都和home.jsp有关,这是用户个人主页,所以需要cas跳转和验证这一环节。在home.jsp里,我进行了session内cas存放数据的验证,

<%
	Object object = request.getSession().getAttribute("_const_cas_assertion_");
	Assertion assertion = (Assertion) object;
	String loginName = "";
	String name = "";
	String email = "";
	String weibo_url = "";
	String github_url = "";
	String interests = "";
	String homepage = "";
	if (object != null) {
	  loginName = assertion.getPrincipal().getName();
	  Map<String, Object> map = assertion.getPrincipal().getAttributes();
	  name = (String) map.get("name");
	  email = (String) map.get("email");
	  weibo_url = (String) map.get("weibo_url");
	  github_url = (String) map.get("github_url");
	  interests = (String) map.get("interests");
	  homepage = (String) map.get("homepage");
	}
 %>

通过获取session里“const_cas_assertion”这个属性的对象,最后在一个map里得到cas存放的信息,为jsp所用。

其他

CAS做登出的时候,需要页面单独做一次session的清空,不然登出的跳转还未登出的效果。更多关于CAS介绍、原理性、入门使用的内容,可以参考CAS解决单点登录SSO,之前我也做了点总结。