• -------------------------------------------------------------
  • ====================================

CAS服务器集群和客户端集群环境下的单点登录和单点注销

技能 dewbay 5年前 (2019-04-12) 2298次浏览 已收录 0个评论 扫描二维码

CAS 的集群环境,包括 CAS 的客户应用是集群环境,以及 CAS 服务本身是集群环境这两种情况。在集群环境下使用 CAS,要解决两个问题,一是单点退出(注销)时,CAS 如何将退出请求正确转发到用户session所在的具体客户应用服务器,而不是转发到其他集群服务器上,二是解决 CAS 服务端集群环境下各种 Ticket 信息的共享。

  1. CAS 集群部署由于 CAS Server 是一个 Web 应用,因此可部署在 Tomcat 等容器中。直接部署 CAS 集群并使用负载均衡配置后,由于每次访问的 CAS Server 不固定,会发生通行证丢失。解决方法:配置 TOMCAT 集群及 Session 复制,解决 CAS Server Session 复制。详细配置方法见”Nginx+Tomcat+Memcached 集群”。
  2. CAS 的 Ticket 信息共享当用户登录后,Ticket 存储在 CAS Server 中,由于这部分数据未保存在 Session 中,仅靠 TOMCAT Session 复制无法解决问题。默认配置下,CAS Server 使用 org.jasig.cas.ticket.registry.DefaultTicketRegistry 把 Ticket 数据保存在 HashMap 中,因此多台 CAS Server 无法共享数据。导致用户登录及退出均存在问题。因此需要将 Ticket 信息进行共享存储,使多台 CAS Server 使用相同的存储区域管理 Ticket。Ticket 信息共享处理比较简单,就是将 Ticket 信息从原来的内存存储变为数据库存储。见”ticketRegistry.xml“文件。处理方法有两种:1 是将 Ticket 信息放在 Redis 内存数据库中,2 是将 Ticket 信息放在 memcached 中,推荐使用 memcached,现在 DMGeoSSO 已经支持这两种方式了,配置文件示例见”ticketRegistry.xml.redis”和 ticketRegistry.xml.memcache。默认配置文件的内容为”ticketRegistry.xml.default”Redis 方式源代码:RedisTicketRegistry.javaMemcached 方式源代码:MemCacheTicketRegistry.java 这里需要注意的是:TGT 和 ST 的超时时间最大只能设置为 30 天(即 2592000 秒),多 1 秒都不行。这是 Memcached 的特性。
  3. CAS 单点注销根据 CAS Server 工作流程,当收到 Logout 请求后,CAS Server 会删除自身存储的有关当前用户的所有 Ticket 票据,”问题二”的解决方法已经解决了多台 CAS Server 删除票据的问题。但随后从 CAS Server 会发起 HTTP POST 请求到应用服务器,该请求中具备”logoutRequest”标志,应用服务器的 SingleSignOutFilter 接收到该请求后在应用服务器端进行用户登出操作。该操作主要是将应用服务器端的 CAS Client 中保存的用户 Session 数据失效,达到客户端登出效果。即,对于 CAS 系统,必须 Server 端和 Client 均进行登出操作,用户才会真正登出。cas 退出采用的是异步操作,客户端是否退出成功也不关心。CAS Server 的这个工作流程,在应用集群部署的情况下带来一系列问题。由于应用服务器集群化,且一般会使用 Session 复制,当 CAS Server 向应用服务器发起 Logout 请求时,仅针对一台服务器发起请求,导致应用服务器没有全部退出,使得用户使用登出操作时,有时可以退出,有时不能退出,用户体验很差。解决方法:采用广播方式,将单台 Tomcat 收到的注销请求广播给集群环境下的所有节点,达到所有服务器都注销的效果。核心代码:DMGeoSSOClient 中的 CasSingleLogoutClusterFilter.java。配置方式,将 DMGeoSSOClient 工程下的 lib 目录下的 jar 包(servlet-api-2.3.jar 除外)以及 dist 下的cas-client-core-3.1.3.jar 包复制到集群环境所有 Tomcat 的 lib 目录,并修改所有 tomcat 的 web.xml,增加过滤器的配置:<filter><filter-name>CAS SLO Cluster Filter</filter-name><filter-class>org.esco.cas.client.CasSingleLogoutClusterFilter</filter-class><init-param><param-name>clientHostName</param-name><param-value>127.0.0.1:8080</param-value></init-param><init-param><param-name>peersUrls</param-name><param-value>http://127.0.0.1:8080,http://127.0.0.1:8081</param-value></init-param></filter>clientHostName 是本 Tomcat 的ip和端口,peersUrls 是集群中所有节点的访问地址(格式为:协议://IP:端口,多个以”,”分隔),注意,这些 IP 地址和端口需要确保集群中所有的节点都能访问到。另外,在集群中的所有需要做单点登录的应用中,web.xml 中增加:<filter-mapping><filter-name>CAS SLO Cluster Filter</filter-name><url-pattern>/*</url-pattern></filter-mapping>注意:这个过滤器需要放在原单点注销的过滤器之前才有效。
  4. Nginx+Tomcat+Memcached 集群(简)nginx 配置:nginx.conf:upstream cluster {server 127.0.0.1:8080;server 127.0.0.1:8081;}PRoxy.conf:server {listen 8888;server_name 127.0.0.1;#access_log logs/access.log main;proxy_connect_timeout 60s;proxy_send_timeout 300s;proxy_read_timeout 300s;proxy_buffer_size 1024k;proxy_buffers 4 1024k;proxy_busy_buffers_size 1024k;proxy_temp_file_write_size 1024k;proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_404;proxy_max_temp_file_size 1024m;location ~ ^/DMGeoPortal/ {proxy_pass http://cluster;proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}location ~ ^/DMGeoSSO/ {proxy_pass http://cluster;proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}Tomcat 配置:context.xml:<Manager className=”de.javakaffee.web.msm.MemcachedBackupSessionManager”memcachedNodes=”n1:172.16.254.69:11211,n2:172.16.254.70:11211″sticky=”false”sessionBackupAsync=”false”sessionBackupTimeout=”18000″transcoderFactoryClass=”de.javakaffee.web.msm.serializer.javolution.JavolutionTranscoderFactory”copyCollectionsForSerialization=”false”/>server.xml:<Engine name=”Catalina” defaultHost=”localhost”>注意:当 sticky 为 false 时,不需要配置 jvmRoute 属性,当 sticky 为 true 时,一定要配置 jvmRoute 属性,且集群中所有 tomcat 的 jvmRoute 属性均不一样。sticky 的属性默认为 true。在 CAS 服务器端集群和客户端集群环境下,需要将 sticky 配置为 false,这样可以避免很多莫名其妙的 session 丢失问题。Sticky 模式:tomcat session 为 主 session, memcached 为备 session。Request 请求到来时, 从 memcached 加载备 session 到 tomcat (仅当 tomcat jvmroute 发生变化时,否则直接取 tomcat session);Request 请求结束时,将 tomcat session 更新至 memcached,以达到主备同步之目的。下面是 sticky 模式时响应的流程图(图片来源网络):Non-Sticky 模式:tomcat session 为 中转 session, memcached1 为主 session,memcached 2 为备 session。Request 请求到来时,从 memcached 2 加载备 session 到 tomcat,(当 容器 中还是没有 session 则从 memcached1 加载主 session 到 tomcat, 这种情况是只有一个 memcached 节点,或者有 memcached1 出错时),Request 请求结束时,将 tomcat session 更新至 主 memcached1 和备 memcached2,并且清除 tomcat session 。以达到主备同步之目的,如下是 non-sticky 模式的响应流程图:(图片来源网络)。requestUriIgnorePattern 属性不要设置。否则在 CAS 服务器端集群和客户端集群环境下有很多问题(包括影响注销功能,不能完全注销),因为我们的单点登录是对所有的资源进行拦截的,不需要设置 requestUriIgnorePattern(URL 忽略)属性。集群中所有 Tomcat 的 lib 下新增的包:javolution-5.4.3.1.jarmemcached-2.6.jarmemcached-session-manager-1.5.1.jarmemcached-session-manager-tc6-1.5.1.jarmsm-javolution-serializer-1.5.1.jarmsm-kryo-serializer-1.5.1.jarmsm-serializer-benchmark-1.5.1.jarmsm-xstream-serializer-1.5.1.jar
  5. Nginx+IIS+Memcached 集群(简)nginx 配置:nginx.conf:upstream dotnetcluster {server 127.0.0.1:80;server 127.0.0.1:81;}proxy.conf:server {listen 8888;server_name 127.0.0.1;#access_log logs/access.log main;proxy_connect_timeout 60s;proxy_send_timeout 300s;proxy_read_timeout 300s;proxy_buffer_size 1024k;proxy_buffers 4 1024k;proxy_busy_buffers_size 1024k;proxy_temp_file_write_size 1024k;proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504 http_404;proxy_max_temp_file_size 1024m;location ~ ^/DMGeoGlobeWeb/ {proxy_pass http://dotnetcluster;proxy_set_header Host $host:8888;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}location ~ ^/DMGeoMIS/ {proxy_pass http://dotnetcluster;proxy_set_header Host $host:8888;proxy_set_header X-Real-IP $remote_addr;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}}这里与 Java 应用稍有不同,注意上述红色加粗部分端口号的配置,该端口号是你最终访问集群服务器的端口号。IIS 配置:将下列 dll 文件放在 Web 应用程序的 bin 目录:Enyim.Caching.dllMemcachedSessionProvider.dll 修改 Web 应用程序的 Web.config 配置:<?xml version=”1.0″ encoding=”utf-8″?><configuration><configSections><sectionGroup name=”sessionManagement”><section name=”memcached” type=”Enyim.Caching.Configuration.MemcachedClientSection, Enyim.Caching” /></sectionGroup></configSections><sessionManagement><memcached protocol=”Binary”><servers><!– make sure you use the same ordering of nodes in every configuration you have –><add address=”172.16.254.69″ port=”11211″ /><add address=”172.16.254.70″ port=”11211″ /></servers><locator type=”MemcachedSessionProvider.SessionNodeLocator, MemcachedSessionProvider” /></memcached></sessionManagement><system.web><sessionState customProvider=”Memcached” mode=”Custom”><providers><add name=”Memcached” type=”MemcachedSessionProvider.SessionProvider, MemcachedSessionProvider” /></providers></sessionState><machineKey validationKey=”3A2122BF7DA69398B43FF26BD658CE428EC417BA” decryptionKey=”5C90C7D3BE69792117E02AE72DDDAFBA853F5FDB3E57BC5C” decryption=”3DES” validation=”SHA1″/></system.web></configuration>上述红色加粗部分是新增的配置项。说明如下:sessionManagement:用来配置 Memcached 连接地址。sessionState:用将配置将 Session 存储在什么地方,这里配置的是自定义,即将 Session 存储在 Memcached 中。machineKey:这是比较关键的配置。如果我们的 Web 应用程序是在同一个 IIS 服务器上,用不同的端口来区分不同的网站应用,那么不需要配置 machineKey;如果我们的 Web 应用程序是在不同的 IIS 服务器上,那么切记一定要配置 machineKey。machineKey 是对密钥进行配置,以便将其用于对 Forms 身份验证 Cookie 数据和视图状态数据进行加密和解密,并将其用于对进程外会话状态标识进行验证。默认情况下,asp.net 的配置是自己动态生成,如果单台服务器当然没问题,但是如果多台服务器负载均衡,machineKey 还采用动态生成的方式,每台服务器上的 machinekey 值不一致,就导致加密出来的结果也不一致,不能共享验证和 ViewState,所以对于多台服务器负载均衡的情况,一定要在每个站点配置相同的 machineKey。machineKey 的生成算法如下:private static string CreateKey(int len){byte[] bytes = new byte[len];new RNGCryptoServiceProvider().GetBytes(bytes);StringBuilder sb = new StringBuilder();for (int i = 0; i < bytes.Length; i++){sb.Append(string.Format(“{0:X2}”, bytes[i]));}return sb.ToString();}调用:string validationKey = CreateKey(20);string decryptionKey = CreateKey(24);string machineKey = string.Format(“<machineKey validationKey=\”{0}\” decryptionKey=\”{1}\” decryption=\”3DES\” validation=\”SHA1\”/>”,validationKey, decryptionKey);

露水湾 , 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:CAS服务器集群和客户端集群环境下的单点登录和单点注销
喜欢 (0)
[]
分享 (0)
关于作者:
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址