SpringMVC对接CAS客户端实现单点登录SSO

业务场景:之前写过CAS服务端的例子,也对接过基于SpringBoot的CAS,不过最近项目要对接第三方的CAS实现单点登录,而我们项目是基于SpringMVC的,所以就摸索了一下对接方案,其它博客可以参考我之前专栏:CAS单点登录系列博客

pom加上cas配置:

1<properties> 2 <cas.client.version>3.4.1</cas.client.version> 3</properties> 4<dependency> 5 <groupId>org.jasig.cas.client</groupId> 6 <artifactId>cas-client-core</artifactId> 7 <version>${cas.client.version}</version> 8 <scope>compile</scope> 9</dependency>

web.xml加上配置

1<!-- CAS单点登录配置--> 2<!-- 单点登出监听器,用于监听单点登出session情况 --> 3 <listener> 4 <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class> 5 </listener> 6 <!-- 该过滤器用于实现单点登出功能 --> 7 <filter> 8 <filter-name>CAS Single Sign Out Filter</filter-name> 9 <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class> 10 <init-param> 11 <param-name>casServerUrlPrefix</param-name> 12 <param-value>http://127.0.0.1:8080/CAS</param-value> 13 </init-param> 14 </filter> 15 <filter-mapping> 16 <filter-name>CAS Single Sign Out Filter</filter-name> 17 <url-pattern>/*</url-pattern> 18 </filter-mapping> 19 <!-- 该过滤器用于实现单点登录功能 --> 20 <filter> 21 <filter-name>CAS Filter</filter-name> 22 <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class> 23 <init-param> 24 <param-name>casServerLoginUrl</param-name> 25 <param-value>http://127.0.0.1:8080/CAS/login</param-value> 26 </init-param> 27 <init-param> 28 <param-name>serverName</param-name> 29 <param-value>http://127.0.0.1:8081</param-value> 30 </init-param> 31 </filter> 32 <filter-mapping> 33 <filter-name>CAS Filter</filter-name> 34 <url-pattern>/*</url-pattern> 35 </filter-mapping> 36 <!-- 该过滤器负责对Ticket的校验工作 --> 37 <filter> 38 <filter-name>CAS Validation Filter</filter-name> 39 <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</filter-class> 40 <init-param> 41 <param-name>casServerUrlPrefix</param-name> 42 <param-value>http://127.0.0.1:8080/CAS</param-value> 43 </init-param> 44 <init-param> 45 <param-name>serverName</param-name> 46 <param-value>http://127.0.0.1:8081</param-value> 47 </init-param> 48 <init-param> 49 <param-name>redirectAfterValidation</param-name> 50 <param-value>true</param-value> 51 </init-param> 52 <init-param> 53 <param-name>useSession</param-name> 54 <param-value>true</param-value> 55 </init-param> 56 <init-param> 57 <param-name>encoding</param-name> 58 <param-value>UTF-8</param-value> 59 </init-param> 60 </filter> 61 <filter-mapping> 62 <filter-name>CAS Validation Filter</filter-name> 63 <url-pattern>/*</url-pattern> 64 </filter-mapping> 65 <!-- 该过滤器负责实现HttpServletRequest请求的包裹, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 --> 66 <filter> 67 <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name> 68 <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class> 69 </filter> 70 <filter-mapping> 71 <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name> 72 <url-pattern>/*</url-pattern> 73 </filter-mapping> 74 <!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。--> 75 <filter> 76 <filter-name>CAS Assertion Thread Local Filter</filter-name> 77 <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class> 78 </filter> 79 <filter-mapping> 80 <filter-name>CAS Assertion Thread Local Filter</filter-name> 81 <url-pattern>/*</url-pattern> 82 </filter-mapping> 83 <!--// CAS单点登录配置 -->

配置好之后,通过AssertionHolder获取登录的用户账号,AssertionThreadLocalFilter过滤器需要配置才能获取,改过滤器通过ThreadLocal保存信息

1protected String getCasLoginUser(){ 2 3 4 5 Assertion assertion = AssertionHolder.getAssertion(); 6 String userName = ""; 7 if (assertion != null) { 8 9 10 11 userName = assertion.getPrincipal().getName(); 12 logger.info("userName:"+userName); 13 } 14 return userName; 15 } 16

基于上面的简单配置基本就能实现cas单点登录和登出,不过配置ip和端口都写在web.xml,以后ip改了,又要翻配置改动,所以可以基于3.0的Servlet api实现动态配置,将配置放在properties

1<dependency> 2 <groupId>javax.servlet</groupId> 3 <artifactId>javax.servlet-api</artifactId> 4 <scope>provided</scope> 5 <version>3.1.0</version> 6</dependency>

实现AbstractAnnotationConfigDispatcherServletInitializer类:

1package com.extra.login.core.servlet; 2 3import com.extra.login.cas.client.filter.authentication.AuthenticationFilter; 4import com.extra.login.cas.client.filter.session.SingleSignOutFilter; 5import com.extra.login.cas.client.util.AssertionThreadLocalFilter; 6import com.extra.login.cas.client.util.CasParamKeyEnum; 7import com.extra.login.cas.client.util.CasPropertiesLoader; 8import com.extra.login.cas.client.util.HttpServletRequestWrapperFilter; 9import org.jasig.cas.client.session.SingleSignOutHttpSessionListener; 10import org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter; 11import org.springframework.stereotype.Component; 12import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; 13 14import javax.servlet.*; 15import java.util.EnumSet; 16 17 18/** 19 * <pre> 20 * 基于Servlet3.0实现动态配置过滤器、监听器、Servlet 21 * </pre> 22 * 23 * <pre> 24 * @author mazq 25 * 修改记录 26 * 修改后版本: 修改人: 修改日期: 2020/08/27 14:33 修改内容: 27 * </pre> 28 */ 29@Component 30public class WebServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 31 32 33 34 35 36 @Override 37 protected Class<?>[] getRootConfigClasses() { 38 39 40 41 return new Class[0]; 42 } 43 44 @Override 45 protected Class<?>[] getServletConfigClasses() { 46 47 48 49 return new Class[0]; 50 } 51 52 @Override 53 protected String[] getServletMappings() { 54 55 56 57 return new String[0]; 58 } 59 60 @Override 61 public void onStartup(ServletContext servletContext) throws ServletException { 62 63 64 65 this.registerCasFilter(servletContext); 66 this.registerCasListener(servletContext); 67 super.onStartup(servletContext); 68 } 69 70 /** 71 * 动态注册CAS过滤器 72 * @Author mazq 73 * @Date 2020/08/27 16:41 74 * @Param [servletContext] 75 * @return void 76 */ 77 protected void registerCasFilter(ServletContext servletContext) { 78 79 80 81 /* CAS单点登录校验过滤器 */ 82 FilterRegistration casFilter = servletContext.addFilter("casFilter", AuthenticationFilter.class); 83 casFilter.setInitParameter("casServerLoginUrl" , CasPropertiesLoader.getValue(CasParamKeyEnum.CAS_SERVER_HOST_LOGIN_URL.getCasParamKey())); 84 casFilter.setInitParameter("serverName" , CasPropertiesLoader.getValue(CasParamKeyEnum.APP_SERVER_HOST_URL.getCasParamKey())); 85 casFilter.setInitParameter("ignorePattern" , "/static/*"); 86 casFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*"); 87 /* CAS单点登录ticket校验过滤器 */ 88 FilterRegistration casValidationFilter = servletContext.addFilter("casValidationFilter", Cas30ProxyReceivingTicketValidationFilter.class); 89 casValidationFilter.setInitParameter("casServerUrlPrefix" , CasPropertiesLoader.getValue(CasParamKeyEnum.CAS_SERVER_HOST_URL.getCasParamKey())); 90 casValidationFilter.setInitParameter("serverName" , CasPropertiesLoader.getValue(CasParamKeyEnum.APP_SERVER_HOST_URL.getCasParamKey())); 91 casValidationFilter.setInitParameter("redirectAfterValidation" , "true"); 92 casValidationFilter.setInitParameter("useSession" , "true"); 93 casValidationFilter.setInitParameter("encoding" , "UTF-8"); 94 casValidationFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*"); 95 /* CAS单点登出过滤器 */ 96 FilterRegistration singleSignOutFilter = servletContext.addFilter("singleSignOutFilter", SingleSignOutFilter.class); 97 singleSignOutFilter.setInitParameter("casServerUrlPrefix" , CasPropertiesLoader.getValue(CasParamKeyEnum.CAS_SERVER_HOST_URL.getCasParamKey())); 98 singleSignOutFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*"); 99 /* HttpServletRequestWrapper过滤器 */ 100 FilterRegistration httpServletRequestWrapperFilter = servletContext.addFilter("httpServletRequestWrapperFilter", HttpServletRequestWrapperFilter.class); 101 httpServletRequestWrapperFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*"); 102 /* AssertionThreadLocal过滤器 */ 103 FilterRegistration assertionThreadLocalFilter = servletContext.addFilter("assertionThreadLocalFilter", AssertionThreadLocalFilter.class); 104 assertionThreadLocalFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*"); 105 } 106 107 /** 108 * 注册CAS监听器 109 * @Author mazq 110 * @Date 2020/08/27 16:43 111 * @Param [servletContext] 112 * @return void 113 */ 114 protected void registerCasListener(ServletContext servletContext){ 115 116 117 118 //注册监听器 119 servletContext.addListener(SingleSignOutHttpSessionListener.class); 120 } 121 122 @Override 123 protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) { 124 125 126 127 return super.registerServletFilter(servletContext, filter); 128 } 129 130 @Override 131 protected void registerContextLoaderListener(ServletContext servletContext) { 132 133 134 135 super.registerContextLoaderListener(servletContext); 136 } 137} 138

不过在一些原有就有自己的登录机制的系统,这里可以将主要的过滤器代码拿来改动,加上开关

1public static boolean isCasLoginMode() { 2 3 4 5 WebConfigService webConfigService = (WebConfigService) ApplicationContextHolder.getApplicationContext().getBean("webConfigService"); 6 boolean isCasMode = webConfigService.getFlag("${casLogin_Boolean}"); 7 if (isCasMode) { 8 9 10 11 return true; 12 } 13 return false; 14 }

获取Spring上下文工具类,filter里不能直接用@Autowired自动装载

1import org.springframework.beans.BeansException; 2import org.springframework.context.ApplicationContext; 3import org.springframework.context.ApplicationContextAware; 4import org.springframework.stereotype.Service; 5 6/** 7 * 获取Spring上下文 8 */ 9@Service 10public class ApplicationContextHolder implements ApplicationContextAware { 11 12 13 14 15 private static ApplicationContext ctx; 16 17 @Override 18 public void setApplicationContext(ApplicationContext applicationContext) 19 throws BeansException { 20 21 22 23 ctx = applicationContext; 24 } 25 26 public static ApplicationContext getApplicationContext() { 27 28 29 30 return ctx; 31 } 32 33 @SuppressWarnings("unchecked") 34 public static <T> T getBean(String beanName) { 35 36 37 38 return (T) ctx.getBean(beanName); 39 } 40 41 public static <T> T getBean(Class<T> clazz) { 42 43 44 45 return ctx.getBean(clazz); 46 } 47} 48

在这里插入图片描述

在这里插入图片描述
源码里的init配置也可以加上开关

cas配置写在cas.properties里,写个工具类进行读取:

1# 是否启动CAS服务 2security.cas.enabled=true 3# CAS服务地址 4security.cas.server.host.url=http://cas.server.org:6342/CAS 5# CAS服务登录地址 6security.cas.server.host.login_url=http://cas.server.org:6342/CAS/login 7# CAS服务登出地址 8security.cas.server.host.logout_url=http://cas.server.org:6342/CAS/logout?service=http://192.168.9.30:8081 9# 应用访问地址 10security.app.server.host.url=http://192.168.9.30:8081

CAS参数枚举类

1package com.extra.login.cas.client.util; 2 3import com.common.utils.config.CasPropertiesLoader; 4 5/** 6 * <pre> 7 * CAS配置参数 8 * </pre> 9 * 10 * <pre> 11 * @author mazq 12 * 修改记录 13 * 修改后版本: 修改人: 修改日期: 2020/08/27 15:46 修改内容: 14 * </pre> 15 */ 16public enum CasParamKeyEnum { 17 18 19 20 // CAS服务地址 21 CAS_SERVER_HOST_URL("security.cas.server.host.url"), 22 // CAS服务登录地址 23 CAS_SERVER_HOST_LOGIN_URL("security.cas.server.host.login_url"), 24 // CAS服务登出地址 25 CAS_SERVER_HOST_LOGOUT_URL("security.cas.server.host.logout_ur"), 26 // 应用访问地址 27 APP_SERVER_HOST_URL("security.app.server.host.url"), 28 // CAS 标识 29 CAS_SIGN("cas"); 30 31 private String casParamKey; 32 33 CasParamKeyEnum(String casParamKey) { 34 35 36 37 this.casParamKey = casParamKey; 38 } 39 40 public String getCasParamKey() { 41 42 43 44 return casParamKey; 45 } 46 47 public void setCasParamKey(String casParamKey) { 48 49 50 51 this.casParamKey = casParamKey; 52 } 53 54 public static void main(String[] args ){ 55 56 57 58 System.out.println(CasPropertiesLoader.getValue("security.cas.server.host.url")); 59 } 60} 61

cas.properties读取工具类:

1package com.extra.login.cas.client.util; 2 3import org.springframework.beans.factory.annotation.Value; 4import org.springframework.context.annotation.Condition; 5import org.springframework.context.annotation.ConditionContext; 6import org.springframework.context.annotation.Conditional; 7import org.springframework.core.type.AnnotatedTypeMetadata; 8import org.springframework.core.type.AnnotationMetadata; 9import org.springframework.core.type.MethodMetadata; 10import org.springframework.stereotype.Component; 11 12import java.util.Properties; 13 14/** 15 * <pre> 16 * CAS配置属性加载类 17 * </pre> 18 * 19 * <pre> 20 * @author mazq 21 * 修改记录 22 * 修改后版本: 修改人: 修改日期: 2020/08/24 15:41 修改内容: 23 * </pre> 24 */ 25@Component 26public class CasPropertiesLoader { 27 28 29 30 31 public final static String CAS_ENABLED = "security.cas.enabled"; 32 public final static String CAS_SERVER_HOST_URL = "security.cas.server.host.url"; 33 public final static String CAS_SERVER_HOST_LOGIN_URL = "security.cas.server.host.login_url"; 34 public final static String CAS_SERVER_HOST_LOGOUT_URL = "security.cas.server.host.logout_url"; 35 public final static String APP_SERVER_HOST_URL = "security.app.server.host.url"; 36 37 public CasPropertiesLoader(){ 38 39 40 } 41 private static Properties props = new Properties(); 42 static{ 43 44 45 46 try { 47 48 49 50 props.load(CasPropertiesLoader .class.getClassLoader().getResourceAsStream("cas.properties")); 51 } catch (Exception e) { 52 53 54 55 e.printStackTrace(); 56 } 57 } 58 public static String getValue(String key){ 59 60 61 62 return props.getProperty(key); 63 } 64 public static void updateProperties(String key,String value) { 65 66 67 68 props.setProperty(key, value); 69 } 70 71 72} 73

对于remoteUser,可以改写HttpServletRequestWrapperFilter源码,实现符合自己的业务:

1package com.extra.login.cas.client.util; 2 3import java.io.IOException; 4import java.security.Principal; 5import java.util.Collection; 6import javax.servlet.*; 7import javax.servlet.http.HttpServletRequest; 8import javax.servlet.http.HttpServletRequestWrapper; 9import javax.servlet.http.HttpSession; 10 11import com.admin.system.oa.service.OaUserService; 12import com.extra.login.hz.cas.client.config.FilterCondition; 13import com.common.filter.SSOFilter; 14import com.common.utils.ApplicationContextHolder; 15import com.common.utils.config.ApprPropConfigUtil; 16import org.apache.commons.lang3.StringUtils; 17import org.jasig.cas.client.authentication.AttributePrincipal; 18import org.jasig.cas.client.configuration.ConfigurationKeys; 19import org.jasig.cas.client.util.AbstractCasFilter; 20import org.jasig.cas.client.util.AbstractConfigurationFilter; 21import org.jasig.cas.client.util.CommonUtils; 22import org.jasig.cas.client.validation.Assertion; 23import org.springframework.util.Assert; 24 25/** 26 * Implementation of a filter that wraps the normal HttpServletRequest with a 27 * wrapper that overrides the following methods to provide data from the 28 * CAS Assertion: 29 * <ul> 30 * <li>{@link HttpServletRequest#getUserPrincipal()}</li> 31 * <li>{@link HttpServletRequest#getRemoteUser()}</li> 32 * <li>{@link HttpServletRequest#isUserInRole(String)}</li> 33 * </ul> 34 * <p/> 35 * This filter needs to be configured in the chain so that it executes after 36 * both the authentication and the validation filters. 37 * 38 * @author Scott Battaglia 39 * @author Marvin S. Addison 40 * @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $ 41 * @since 3.0 42 */ 43public final class HttpServletRequestWrapperFilter extends AbstractConfigurationFilter { 44 45 46 47 48 /** Name of the attribute used to answer role membership queries */ 49 private String roleAttribute; 50 51 /** Whether or not to ignore case in role membership queries */ 52 private boolean ignoreCase; 53 54 private String sessionKeyName = ApprPropConfigUtil.get("session.keyName"); 55 56 // 默认sessionKey 57 private static String DEFAULT_SESSION_KEY_NAME = "ssoLoginUser"; 58 59 public void destroy() { 60 61 62 63 // nothing to do 64 } 65 66 /** 67 * Wraps the HttpServletRequest in a wrapper class that delegates 68 * <code>request.getRemoteUser</code> to the underlying Assertion object 69 * stored in the user session. 70 */ 71 public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, 72 final FilterChain filterChain) throws IOException, ServletException { 73 74 75 76 if (!FilterCondition.isCasLoginMode()) { 77 78 79 // 产品模式跳过 80 filterChain.doFilter(servletRequest, servletResponse); 81 return; 82 } 83 final HttpServletRequest request = (HttpServletRequest) servletRequest; 84 if (SSOFilter.notNeedLoginUrl.contains(request.getRequestURI()) || request.getRequestURI().startsWith("/Common/static")) { 85 86 87 88 filterChain.doFilter(request, servletResponse); 89 return; 90 } 91 final AttributePrincipal principal = retrievePrincipalFromSessionOrRequest(servletRequest); 92 logger.info("cas用户账号:{}",principal.getName()); 93 //String userCode = this.getApprUser(principal.getName()); 94 filterChain.doFilter(new HttpServletRequestWrapperFilter.CasHttpServletRequestWrapper((HttpServletRequest) servletRequest), 95 servletResponse); 96 } 97 98 @Deprecated 99 protected String getApprUser(String casUser) { 100 101 102 103 OaUserService oaUserService = (OaUserService) ApplicationContextHolder.getApplicationContext().getBean("oaUserService"); 104 String apprUserCode = oaUserService.getApproveUserCodeBySysType(casUser, CasParamKeyEnum.CAS_SIGN.getCasParamKey()); 105 logger.info("cas对应审批用户账号:{}",apprUserCode); 106 Assert.state(StringUtils.isNotBlank(apprUserCode), "请联系管理员配置单点登录关联数据!"); 107 return apprUserCode; 108 } 109 110 protected AttributePrincipal retrievePrincipalFromSessionOrRequest(final ServletRequest servletRequest) { 111 112 113 114 final HttpServletRequest request = (HttpServletRequest) servletRequest; 115 final HttpSession session = request.getSession(false); 116 final Assertion assertion = (Assertion) (session == null ? request 117 .getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session 118 .getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION)); 119 120 return assertion == null ? null : assertion.getPrincipal(); 121 } 122 123 public void init(final FilterConfig filterConfig) throws ServletException { 124 125 126 127 if (FilterCondition.isHzCasLoginMode()) { 128 129 130 131 super.init(filterConfig); 132 this.roleAttribute = getString(ConfigurationKeys.ROLE_ATTRIBUTE); 133 this.ignoreCase = getBoolean(ConfigurationKeys.IGNORE_CASE); 134 } 135 } 136 137 final class CasHttpServletRequestWrapper extends HttpServletRequestWrapper { 138 139 140 141 String userCode; 142 CasHttpServletRequestWrapper(HttpServletRequest request) { 143 144 145 146 super(request); 147 this.userCode = (String) request.getSession() 148 .getAttribute(org.apache.commons.lang3.StringUtils.isBlank(sessionKeyName)?DEFAULT_SESSION_KEY_NAME:sessionKeyName); 149 } 150 @Override 151 public String getRemoteUser() { 152 153 154 155 return userCode; 156 } 157 158 } 159} 160

根据cas用户账号,找业务系统关联数据,并丢数据到session

1String userName = this.getCasLoginUser(); 2logger.info("CAS用户账号:"+userName); 3String apprUserCode=oaUserService.getUserCodeBySysType(userName,CasParamKeyEnum.CAS_SIGN.getCasParamKey()); 4logger.info("业务系统对应的userCode:"+apprUserCode); 5String sessionKey = org.springframework.util.StringUtils.isEmpty(ApprPropConfigUtil.get("session.keyName"))?"ssoLoginUser":ApprPropConfigUtil.get("session.keyName"); 6HttpSession session = request.getSession(); 7if (!StringUtils.isEmpty(apprUserCode)) { 8 9 10 11 session.setAttribute(sessionKey, apprUserCode); 12}

获取CAS用户账号:

1protected String getCasLoginUser(){ 2 3 4 5 Assertion assertion = AssertionHolder.getAssertion(); 6 String userName = ""; 7 if (assertion != null) { 8 9 10 11 userName = assertion.getPrincipal().getName(); 12 logger.info("userName:"+userName); 13 } 14 return userName; 15 }

本文同步分享在 博客“smileNicky”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

【实践篇】基于CAS的单点登录实践之路

上个月我负责的系统SSO升级,对接京东ERP系统,这也让我想起了之前我做过一个单点登录的项目。想来单点登录有很多实现方案,不过最主流的还是基于CAS的方案,所以我也就分享一下我的CAS实践之路。

CAS 实现站内单点登录及实现第三方 OAuth、OpenId 登录(一)

一、CAS介绍    CAS是Yale大学发起的一个开源项目,旨在为Web应用系统提供一种可靠的单点登录方法,CAS在2004年12月正式成为JASIG的一个项目。CAS具有以下特点:开源的企业级单点登录解决方案CASServer为需要独立部署的Web应用CASClient支持非

CAS 4.1.x 单点登出(退出登录)的原理解析

  我们在项目中使用了cas作为单点登录的解决方案,当在集成shiro做统一权限控制的时候,发现单点退出登录有坑,所以啃了一下CAS的单点登出的源码,在此分享一下。1、回顾单点登录中一些关键事件  在解析CAS单点登出的原理之前,我们先回顾一下在单点登录过程中,CAS服务器和CAS客户端都做了一些什么事,这些事

SpringMVC对接CAS客户端实现单点登录SSO - HelloWorld