CAS 单点登录系统

 

一、什么是单点登录


单点登录(Sign Sion On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。对于存在诸多子系统且子系统分别部署到不同的服务器中,那么使用传统的 session 是无法解决的,就需要使用单点登录技术来解决。

如图:第一次访问应用系统1时,会自动跳转到认证系统进行登录,当登录成功时返回 ticket(票据)存储在用户本地,类似于 Cookie。当用户第二次访问应用系统2时,会将 ticket 传送过去,应用系统2与认证系统之间进行 ticket 的验证(系统内部的交互,不会进行页面之间的跳转,用户基本感受不到)验证成功后进入应用系统2中。其余系统访问与应用系统2相同。

二、什么是 CAS


CAS 是 Yale 大学发起的一个开源项目,目的为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 04 年正式成为 JA-SIG 的一个项目。CAS 具有如下特点:
 ●  开源的企业级单点登录解决方案。
 ●  CAS Server 为需要独立部署的 Web 应用,换句话说就是一个 war 包,直接放入Tomcat 进行使用。
 ●  CAS Client 支持非常多的客户端(指的是非常多的 Web 应用),包括 Java、.Net、PHP、Apache、Ruby 等

从结构上看,CAS 包含两个部分:CAS ServerCAS ClientCAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client(用户的应用系统) 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server,下图是 CAS 最基本的协议过程。

SSO 单点登录访问流程主要有以下步骤:
  1)、访问服务:SSO 客户端发送请求访问应用系统提供的服务资源。
  2)、定向认证:SSO 客户端会重定向用户请求到 SSO 服务器。
  3)、用户认证:用户身份认证,认证成功后返回 Ticket 票据信息。
  4)、发送票据:SSO 服务器会产生一个随机的 Server Ticket。
  5)、验证票据:SSO 服务器验证票据 Service Ticket 的合法性,验证通过后,允许客户端访问服务。
  6)、传送用户信息:SSO 服务器验证票据通过后,传输用户认证结果信息给客户端。

三、CAS 服务端部署


CAS 服务端其实就是一个 war 包(cas-server-webapp-4.0.0.war),将其改名为 cas.war 放入 Tomcat 目录下的 webapps 下。启动 Tomcat 自动解压 war 包,在浏览器中输入 http://localhost:8080/cas/login 可以看到登录页面:默认登录用户名 casuser,密码 Mellon

四、服务端配置


【1】如果不希望用 8080 端口访问 CAS 可以修改端口:打开 Tomcat 目录 conf/server.xml 修改如下内容:将 8080 修改为你想要的端口(9100)

1 <!--<Connector port="8080" protocol="HTTP/1.1"
2            connectionTimeout="20000"
3            redirectPort="8443" />(原配置文件)-->
4 <Connector port="9100" protocol="HTTP/1.1"
5            connectionTimeout="20000"
6            redirectPort="8443" />

修改 CAS 配置文件:cas 项目中的 WEB-INF/cas.properties

1 #server.name=http://localhost:8080(原配置内容)   修改为自己的IP和端口
2 server.name=http://192.68.88.129:9100

【2】去除 Https 认证

CAS默认使用的是 HTTPS 协议,如果使用 HTTPS 协议需要 SSL 安全证书(需要向特定的机构申请和购买)。如果安全要求不高或者是开发测试阶段, 可使用 HTTP协议。我们这里讲解通过修改配置,让 CAS使用 HTTP协议。 

修改 cas 的 WEB-INF/deployerConfigContext.xml 修改配置文件:这里需要增加参数 p:requireSecure="false", requireSecure 属性意思为是否需要安全验证,即 HTTPS,false 为不采用

1 <bean id="proxyAuthenticationHandler"
2       class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
3       p:httpClient-ref="httpClient" />

修改 cas 的 /WEB-INF/spring-configuration/ticketGrantingTicketCookieGenerator.xml 找到下面配置:

参数 p:cookieSecure="true",同理为HTTPS验证相关,true为采用 HTTPS 验证,false 为不采用 https 验证。
参数 p:cookieMaxAge="-1",是 COOKIE的最大生命周期,-1为无生命周期,即只在当前打开的窗口有效,关闭或重新打开其它窗口,仍会要求验证。可以根据需要修改为大于0的数字,比如3600等,意思是在 3600秒内,打开任意窗口,都不需要验证。

我们这里将 cookieSecure改为false ,  cookieMaxAge 改为3600

1 <bean id="ticketGrantingTicketCookieGenerator" 
2           class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
3     p:cookieSecure="true"
4     p:cookieMaxAge="-1"
5     p:cookieName="CASTGC"
6     p:cookiePath="/cas" />

修改 cas的 WEB-INF/spring-configuration/warnCookieGenerator.xml 找到下面配置:这里将cookieSecure改为false ,  cookieMaxAge 改为3600

1 <bean id="warnCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
2     p:cookieSecure="true"
3     p:cookieMaxAge="-1"
4     p:cookieName="CASPRIVACY"
5     p:cookiePath="/cas" />

五、CAS 入门客户端 Demo


【1】搭建 maven Project 工程(cas_demo1 与 cas_demo2 两个工程)引入 cas 客户端依赖并定制 tomcat 运行端口分别为 9001 和 9002

 1 <dependencies>
 2     <!-- cas -->  
 3     <dependency>  
 4         <groupId>org.jasig.cas.client</groupId>  
 5         <artifactId>cas-client-core</artifactId>  
 6         <version>3.3.3</version>  
 7     </dependency>          
 8     
 9     <dependency>
10         <groupId>javax.servlet</groupId>
11         <artifactId>servlet-api</artifactId>
12         <version>2.5</version>  
13         <scope>provided</scope>
14     </dependency>
15 </dependencies>  
16 <build>  
17   <plugins>
18       <plugin>  
19           <groupId>org.apache.maven.plugins</groupId>  
20           <artifactId>maven-compiler-plugin</artifactId>  
21           <version>2.3.2</version>  
22           <configuration>  
23               <source>1.7</source>  
24               <target>1.7</target>  
25           </configuration>  
26       </plugin>  
27       <plugin>
28       <groupId>org.apache.tomcat.maven</groupId>
29       <artifactId>tomcat7-maven-plugin</artifactId>
30       <configuration>
31           <!-- 指定端口 -->
32           <port>9002</port>
33           <!-- 请求路径 -->
34           <path>/</path>
35       </configuration>
36       </plugin>
37   </plugins>  
38 </build>

【2】webapp 文件下创建 WEB-INF/web.xml 文件,内容如下:需要修改本地服务的地址和 CAS 服务器的地址。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3     xmlns="http://java.sun.com/xml/ns/javaee"
 4     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
 5     version="2.5">    
 6     
 7     <!-- ======================== 单点登录开始 ======================== -->  
 8     <!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置 -->  
 9     <listener>  
10         <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>  
11     </listener>  
12   
13     <!-- 该过滤器用于实现单点登出功能,可选配置。 -->  
14     <filter>  
15         <filter-name>CAS Single Sign Out Filter</filter-name>  
16         <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>  
17     </filter>  
18     <filter-mapping>  
19         <filter-name>CAS Single Sign Out Filter</filter-name>  
20         <url-pattern>/*</url-pattern>  
21     </filter-mapping>  
22   
23     <!-- 该过滤器负责用户的认证工作,必须启用它 -->  
24     <filter>  
25         <filter-name>CASFilter</filter-name>  
26         <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>  
27         <init-param>  
28             <param-name>casServerLoginUrl</param-name>  
29             <!--这里的server是服务端的IP -->  
30             <param-value>http://192.168.88.129:9100/cas/login</param-value>  
31         </init-param>  
32         <init-param>  
33             <param-name>serverName</param-name>  
34             <!-- 当前系统的地址 因为cas 认证成功后需要跳转到当前的系统中 -->
35             <param-value>http://localhost:9002</param-value>
36         </init-param>  
37     </filter>  
38     <filter-mapping>  
39         <filter-name>CASFilter</filter-name>  
40         <url-pattern>/*</url-pattern>  
41     </filter-mapping>  
42   
43     <!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->  
44     <filter>  
45         <filter-name>CAS Validation Filter</filter-name>  
46         <filter-class>  
47             org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>  
48         <init-param>  
49             <param-name>casServerUrlPrefix</param-name>  
50             <param-value>http://192.168.88.129:9100/cas</param-value>  
51         </init-param>  
52         <init-param>  
53             <param-name>serverName</param-name>  
54             <param-value>http://localhost:9002</param-value>
55         </init-param>  
56     </filter>  
57     <filter-mapping>  
58         <filter-name>CAS Validation Filter</filter-name>  
59         <url-pattern>/*</url-pattern>  
60     </filter-mapping>  
61   
62     <!-- 该过滤器负责实现HttpServletRequest请求的包裹, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->  
63     <filter>  
64         <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>  
65         <filter-class>  
66             org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>  
67     </filter>  
68     <filter-mapping>  
69         <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>  
70         <url-pattern>/*</url-pattern>  
71     </filter-mapping>  
72   
73     <!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 -->  
74     <filter>  
75         <filter-name>CAS Assertion Thread Local Filter</filter-name>  
76         <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>  
77     </filter>  
78     <filter-mapping>  
79         <filter-name>CAS Assertion Thread Local Filter</filter-name>  
80         <url-pattern>/*</url-pattern>  
81     </filter-mapping>  
82   
83     <!-- ======================== 单点登录结束 ======================== -->  
84 </web-app>

【3】webapp 中编写 index.jsp 页面,保持页面中的内容不同即可(用于服务两个服务)

 1 <%@ page language="java" contentType="text/html; charset=utf-8"
 2     pageEncoding="utf-8"%>
 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 4 <html>
 5 <head>
 6 <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
 7 <title>CAS DEMO2</title>
 8 </head>
 9 <body>
10 欢迎来到CAS DEMO2
11 <%=request.getRemoteUser()%>
12 </body>
13 </html>

【4】通过 Run As - maven build... - Golas:clean tomcat7:run 当第一次访问本地项目 demo1 时,自动跳转至 CAS 登录页面,登录成功后跳转至 Demo1 的 index.jsp 页面中,当再次访问本地项目 demo2 时,就不用进行登录直接,进入项目 demo2 的index.jsp 页面:

六、单点退出登录


单点登录链接:http://192.168.88.129:9100/cas/logout 既退出所有节点的用户登录。便可看到登出提示页面:

如果我们希望退出登录后,自动跳转到某个自己设定的页面,需要做如下修改:
【1】修改 cas系统的配置文件 cas-servlet.xml ,将 p:followServiceRedirects 中的 false 修改为 true 既可以重定向。

1   <bean id="logoutAction" class="org.jasig.cas.web.flow.LogoutAction"
2         p:servicesManager-ref="servicesManager"
3         p:followServiceRedirects="${cas.logout.followServiceRedirects:false}"/>

【2】改为 true 后,可以在退出时跳转页面到目标页面,修改 index.jsp 的退出链接,在连接中添加 service= 目标地址

<a href="http://localhost:9100/cas/logout?service=http://www.baidu.com">退出登录</a>

七、CAS 服务端数据源设置 (用户信息从数据库中获取)


修改cas服务端中 web-inf 下 deployerConfigContext.xml ,添加如下配置

 1 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"  
 2           p:driverClass="com.mysql.jdbc.Driver"  
 3           p:jdbcUrl="jdbc:mysql://127.0.0.1:3306/pinyougoudb?characterEncoding=utf8"  
 4           p:user="root"  
 5           p:password="123456" /> 
 6 <!--密码加密的算法-->
 7 <bean id="passwordEncoder"  class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"  
 8     c:encodingAlgorithm="MD5"  
 9     p:characterEncoding="UTF-8" /> 
10 <bean id="dbAuthHandler"  
11       class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"  
12       p:dataSource-ref="dataSource"  
13       p:sql="select password from tb_user where username = ?"  
14       p:passwordEncoder-ref="passwordEncoder"/>  

然后在配置文件开始部分找到如下配置

 1 <bean id="authenticationManager" class="org.jasig.cas.authentication.PolicyBasedAuthenticationManager">
 2         <constructor-arg>
 3             <map>               
 4                 <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
 5                 <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" />
 6             </map>
 7         </constructor-arg>      
 8         <property name="authenticationPolicy">
 9             <bean class="org.jasig.cas.authentication.AnyAuthenticationPolicy" />
10         </property>
11 </bean>

其中 <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" /> 一句是使用固定的用户名和密码,我们在下面可以看到这两个bean ,如果我们使用数据库认证用户名和密码,需要将这句注释掉。添加下面这一句配置 <entry key-ref="dbAuthHandler" value-ref="primaryPrincipalResolver"/>  修改后如下:

1 <constructor-arg>
2     <map>
3         <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
4         <entry key-ref="dbAuthHandler" value-ref="primaryPrincipalResolver" />
5     </map>
6 </constructor-arg>

将上面配置的三个 Bean 所涉及的 jar 包放入webapps\cas\WEB-INF\lib 下  

八、优缺点


优点 :用户身份信息独立管理,更好的分布式管理。同时, 可以自己扩展安全策略;
缺点:认证服务器访问压力较大。需要根据自己系统的情况判断是否选择使用SSO;


 ----架构师资料,关注公众号获取----

posted @ 2020-11-19 22:47  Java程序员进阶  阅读(837)  评论(0编辑  收藏  举报