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

Easter79
• 阅读 612

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

pom加上cas配置:

<properties>
    <cas.client.version>3.4.1</cas.client.version>
</properties>
<dependency>
    <groupId>org.jasig.cas.client</groupId>
    <artifactId>cas-client-core</artifactId>
    <version>${cas.client.version}</version>
    <scope>compile</scope>
</dependency>

web.xml加上配置

<!-- CAS单点登录配置-->
<!-- 单点登出监听器,用于监听单点登出session情况 -->
    <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>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <param-value>http://127.0.0.1:8080/CAS</param-value>
        </init-param>
    </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>http://127.0.0.1:8080/CAS/login</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>http://127.0.0.1:8081</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.Cas30ProxyReceivingTicketValidationFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <param-value>http://127.0.0.1:8080/CAS</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>http://127.0.0.1:8081</param-value>
        </init-param>
        <init-param>
            <param-name>redirectAfterValidation</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>useSession</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</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来获取用户的登录名。-->
    <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>
    <!--// CAS单点登录配置 -->

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

protected String getCasLoginUser(){
   
   
   
        Assertion assertion = AssertionHolder.getAssertion();
        String userName = "";
        if (assertion != null) {
   
   
   
            userName = assertion.getPrincipal().getName();
            logger.info("userName:"+userName);
        }
        return userName;
    }

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

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <scope>provided</scope>
    <version>3.1.0</version>
</dependency>

实现AbstractAnnotationConfigDispatcherServletInitializer类:

package com.extra.login.core.servlet;

import com.extra.login.cas.client.filter.authentication.AuthenticationFilter;
import com.extra.login.cas.client.filter.session.SingleSignOutFilter;
import com.extra.login.cas.client.util.AssertionThreadLocalFilter;
import com.extra.login.cas.client.util.CasParamKeyEnum;
import com.extra.login.cas.client.util.CasPropertiesLoader;
import com.extra.login.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import javax.servlet.*;
import java.util.EnumSet;


/**
 * <pre>
 *      基于Servlet3.0实现动态配置过滤器、监听器、Servlet
 * </pre>
 *
 * <pre>
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2020/08/27 14:33  修改内容:
 * </pre>
 */
@Component
public class WebServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer  {
   
   
   


    @Override
    protected Class<?>[] getRootConfigClasses() {
   
   
   
        return new Class[0];
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
   
   
   
        return new Class[0];
    }

    @Override
    protected String[] getServletMappings() {
   
   
   
        return new String[0];
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
   
   
   
        this.registerCasFilter(servletContext);
        this.registerCasListener(servletContext);
        super.onStartup(servletContext);
    }

    /**
     *  动态注册CAS过滤器
     * @Author mazq
     * @Date 2020/08/27 16:41
     * @Param [servletContext]
     * @return void
     */
    protected void registerCasFilter(ServletContext servletContext) {
   
   
   
        /* CAS单点登录校验过滤器 */
        FilterRegistration casFilter = servletContext.addFilter("casFilter", AuthenticationFilter.class);
        casFilter.setInitParameter("casServerLoginUrl" , CasPropertiesLoader.getValue(CasParamKeyEnum.CAS_SERVER_HOST_LOGIN_URL.getCasParamKey()));
        casFilter.setInitParameter("serverName" , CasPropertiesLoader.getValue(CasParamKeyEnum.APP_SERVER_HOST_URL.getCasParamKey()));
        casFilter.setInitParameter("ignorePattern" , "/static/*");
        casFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*");
        /* CAS单点登录ticket校验过滤器 */
        FilterRegistration casValidationFilter = servletContext.addFilter("casValidationFilter", Cas30ProxyReceivingTicketValidationFilter.class);
        casValidationFilter.setInitParameter("casServerUrlPrefix" , CasPropertiesLoader.getValue(CasParamKeyEnum.CAS_SERVER_HOST_URL.getCasParamKey()));
        casValidationFilter.setInitParameter("serverName" , CasPropertiesLoader.getValue(CasParamKeyEnum.APP_SERVER_HOST_URL.getCasParamKey()));
        casValidationFilter.setInitParameter("redirectAfterValidation" , "true");
        casValidationFilter.setInitParameter("useSession" , "true");
        casValidationFilter.setInitParameter("encoding" , "UTF-8");
        casValidationFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*");
        /* CAS单点登出过滤器 */
        FilterRegistration singleSignOutFilter = servletContext.addFilter("singleSignOutFilter", SingleSignOutFilter.class);
        singleSignOutFilter.setInitParameter("casServerUrlPrefix" , CasPropertiesLoader.getValue(CasParamKeyEnum.CAS_SERVER_HOST_URL.getCasParamKey()));
        singleSignOutFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*");
        /* HttpServletRequestWrapper过滤器 */
        FilterRegistration httpServletRequestWrapperFilter = servletContext.addFilter("httpServletRequestWrapperFilter", HttpServletRequestWrapperFilter.class);
        httpServletRequestWrapperFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*");
        /* AssertionThreadLocal过滤器 */
        FilterRegistration assertionThreadLocalFilter = servletContext.addFilter("assertionThreadLocalFilter", AssertionThreadLocalFilter.class);
        assertionThreadLocalFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class) , true, "/*");
    }

    /**
     * 注册CAS监听器
     * @Author mazq
     * @Date 2020/08/27 16:43
     * @Param [servletContext]
     * @return void
     */
    protected void registerCasListener(ServletContext servletContext){
   
   
   
        //注册监听器
        servletContext.addListener(SingleSignOutHttpSessionListener.class);
    }

    @Override
    protected FilterRegistration.Dynamic registerServletFilter(ServletContext servletContext, Filter filter) {
   
   
   
        return super.registerServletFilter(servletContext, filter);
    }

    @Override
    protected void registerContextLoaderListener(ServletContext servletContext) {
   
   
   
        super.registerContextLoaderListener(servletContext);
    }
}

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

public static boolean isCasLoginMode() {
   
   
   
        WebConfigService webConfigService = (WebConfigService) ApplicationContextHolder.getApplicationContext().getBean("webConfigService");
        boolean isCasMode = webConfigService.getFlag("${casLogin_Boolean}");
        if (isCasMode) {
   
   
   
            return true;
        }
        return false;
    }

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

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

/**
 * 获取Spring上下文
 */
@Service
public class ApplicationContextHolder implements ApplicationContextAware {
   
   
   
    
    private static ApplicationContext ctx;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
   
   
   
        ctx = applicationContext;
    }

    public static ApplicationContext getApplicationContext() {
   
   
   
        return ctx;
    }
    
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanName) {
   
   
   
        return (T) ctx.getBean(beanName);
    }
    
    public static <T> T getBean(Class<T> clazz) {
   
   
   
        return ctx.getBean(clazz);
    }
}

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

SpringMVC对接CAS客户端实现单点登录SSO
源码里的init配置也可以加上开关

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

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

CAS参数枚举类

package com.extra.login.cas.client.util;

import com.common.utils.config.CasPropertiesLoader;

/**
 * <pre>
 *      CAS配置参数
 * </pre>
 *
 * <pre>
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2020/08/27 15:46  修改内容:
 * </pre>
 */
public enum CasParamKeyEnum {
   
   
   
    // CAS服务地址
    CAS_SERVER_HOST_URL("security.cas.server.host.url"),
    // CAS服务登录地址
    CAS_SERVER_HOST_LOGIN_URL("security.cas.server.host.login_url"),
    // CAS服务登出地址
    CAS_SERVER_HOST_LOGOUT_URL("security.cas.server.host.logout_ur"),
    // 应用访问地址
    APP_SERVER_HOST_URL("security.app.server.host.url"),
    // CAS 标识
    CAS_SIGN("cas");

    private String casParamKey;

    CasParamKeyEnum(String casParamKey) {
   
   
   
        this.casParamKey = casParamKey;
    }

    public String getCasParamKey() {
   
   
   
        return casParamKey;
    }

    public void setCasParamKey(String casParamKey) {
   
   
   
        this.casParamKey = casParamKey;
    }

    public static void main(String[] args ){
   
   
   
        System.out.println(CasPropertiesLoader.getValue("security.cas.server.host.url"));
    }
}

cas.properties读取工具类:

package com.extra.login.cas.client.util;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.MethodMetadata;
import org.springframework.stereotype.Component;

import java.util.Properties;

/**
 * <pre>
 *      CAS配置属性加载类
 * </pre>
 *
 * <pre>
 * @author mazq
 * 修改记录
 *    修改后版本:     修改人:  修改日期: 2020/08/24 15:41  修改内容:
 * </pre>
 */
@Component
public class CasPropertiesLoader {
   
   
   

    public final static String CAS_ENABLED = "security.cas.enabled";
    public final static String CAS_SERVER_HOST_URL = "security.cas.server.host.url";
    public final static String CAS_SERVER_HOST_LOGIN_URL = "security.cas.server.host.login_url";
    public final static String CAS_SERVER_HOST_LOGOUT_URL = "security.cas.server.host.logout_url";
    public final static String APP_SERVER_HOST_URL = "security.app.server.host.url";

    public CasPropertiesLoader(){
   
   
   }
    private static Properties props = new Properties();
    static{
   
   
   
        try {
   
   
   
            props.load(CasPropertiesLoader .class.getClassLoader().getResourceAsStream("cas.properties"));
        } catch (Exception e) {
   
   
   
            e.printStackTrace();
        }
    }
    public static String getValue(String key){
   
   
   
        return props.getProperty(key);
    }
    public static void updateProperties(String key,String value) {
   
   
   
        props.setProperty(key, value);
    }


}

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

package com.extra.login.cas.client.util;

import java.io.IOException;
import java.security.Principal;
import java.util.Collection;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpSession;

import com.admin.system.oa.service.OaUserService;
import com.extra.login.hz.cas.client.config.FilterCondition;
import com.common.filter.SSOFilter;
import com.common.utils.ApplicationContextHolder;
import com.common.utils.config.ApprPropConfigUtil;
import org.apache.commons.lang3.StringUtils;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.AbstractConfigurationFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.util.Assert;

/**
 * Implementation of a filter that wraps the normal HttpServletRequest with a
 * wrapper that overrides the following methods to provide data from the
 * CAS Assertion:
 * <ul>
 * <li>{@link HttpServletRequest#getUserPrincipal()}</li>
 * <li>{@link HttpServletRequest#getRemoteUser()}</li>
 * <li>{@link HttpServletRequest#isUserInRole(String)}</li>
 * </ul>
 * <p/>
 * This filter needs to be configured in the chain so that it executes after
 * both the authentication and the validation filters.
 *
 * @author Scott Battaglia
 * @author Marvin S. Addison
 * @version $Revision: 11729 $ $Date: 2007-09-26 14:22:30 -0400 (Tue, 26 Sep 2007) $
 * @since 3.0
 */
public final class HttpServletRequestWrapperFilter extends AbstractConfigurationFilter {
   
   
   

    /** Name of the attribute used to answer role membership queries */
    private String roleAttribute;

    /** Whether or not to ignore case in role membership queries */
    private boolean ignoreCase;

    private String sessionKeyName = ApprPropConfigUtil.get("session.keyName");

    // 默认sessionKey
    private static String DEFAULT_SESSION_KEY_NAME = "ssoLoginUser";

    public void destroy() {
   
   
   
        // nothing to do
    }

    /**
     * Wraps the HttpServletRequest in a wrapper class that delegates
     * <code>request.getRemoteUser</code> to the underlying Assertion object
     * stored in the user session.
     */
    public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse,
                         final FilterChain filterChain) throws IOException, ServletException {
   
   
   
        if (!FilterCondition.isCasLoginMode()) {
   
   
    // 产品模式跳过
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        final HttpServletRequest request = (HttpServletRequest) servletRequest;
        if (SSOFilter.notNeedLoginUrl.contains(request.getRequestURI()) || request.getRequestURI().startsWith("/Common/static")) {
   
   
   
            filterChain.doFilter(request, servletResponse);
            return;
        }
        final AttributePrincipal principal = retrievePrincipalFromSessionOrRequest(servletRequest);
        logger.info("cas用户账号:{}",principal.getName());
        //String userCode = this.getApprUser(principal.getName());
        filterChain.doFilter(new HttpServletRequestWrapperFilter.CasHttpServletRequestWrapper((HttpServletRequest) servletRequest),
                servletResponse);
    }

    @Deprecated
    protected String getApprUser(String casUser) {
   
   
   
        OaUserService oaUserService = (OaUserService) ApplicationContextHolder.getApplicationContext().getBean("oaUserService");
        String apprUserCode = oaUserService.getApproveUserCodeBySysType(casUser, CasParamKeyEnum.CAS_SIGN.getCasParamKey());
        logger.info("cas对应审批用户账号:{}",apprUserCode);
        Assert.state(StringUtils.isNotBlank(apprUserCode), "请联系管理员配置单点登录关联数据!");
        return apprUserCode;
    }

    protected AttributePrincipal retrievePrincipalFromSessionOrRequest(final ServletRequest servletRequest) {
   
   
   
        final HttpServletRequest request = (HttpServletRequest) servletRequest;
        final HttpSession session = request.getSession(false);
        final Assertion assertion = (Assertion) (session == null ? request
                .getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION) : session
                .getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION));

        return assertion == null ? null : assertion.getPrincipal();
    }

    public void init(final FilterConfig filterConfig) throws ServletException {
   
   
   
        if (FilterCondition.isHzCasLoginMode()) {
   
   
   
            super.init(filterConfig);
            this.roleAttribute = getString(ConfigurationKeys.ROLE_ATTRIBUTE);
            this.ignoreCase = getBoolean(ConfigurationKeys.IGNORE_CASE);
        }
    }

    final class CasHttpServletRequestWrapper extends HttpServletRequestWrapper {
   
   
   
        String userCode;
        CasHttpServletRequestWrapper(HttpServletRequest request) {
   
   
   
            super(request);
            this.userCode = (String) request.getSession()
                    .getAttribute(org.apache.commons.lang3.StringUtils.isBlank(sessionKeyName)?DEFAULT_SESSION_KEY_NAME:sessionKeyName);
        }
        @Override
        public String getRemoteUser() {
   
   
   
            return userCode;
        }

    }
}

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

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

获取CAS用户账号:

protected String getCasLoginUser(){
   
   
   
        Assertion assertion = AssertionHolder.getAssertion();
        String userName = "";
        if (assertion != null) {
   
   
   
            userName = assertion.getPrincipal().getName();
            logger.info("userName:"+userName);
        }
        return userName;
    }

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

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
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
【实践篇】基于CAS的单点登录实践之路
上个月我负责的系统SSO升级,对接京东ERP系统,这也让我想起了之前我做过一个单点登录的项目。想来单点登录有很多实现方案,不过最主流的还是基于CAS的方案,所以我也就分享一下我的CAS实践之路。
Stella981 Stella981
2年前
CAS 实现站内单点登录及实现第三方 OAuth、OpenId 登录(一)
一、CAS介绍    CAS是Yale大学发起的一个开源项目,旨在为Web应用系统提供一种可靠的单点登录方法,CAS在2004年12月正式成为JASIG的一个项目。CAS具有以下特点:开源的企业级单点登录解决方案CASServer为需要独立部署的Web应用CASClient支持非
Wesley13 Wesley13
2年前
CAS 4.1.x 单点登出(退出登录)的原理解析
  我们在项目中使用了cas作为单点登录的解决方案,当在集成shiro做统一权限控制的时候,发现单点退出登录有坑,所以啃了一下CAS的单点登出的源码,在此分享一下。1、回顾单点登录中一些关键事件  在解析CAS单点登出的原理之前,我们先回顾一下在单点登录过程中,CAS服务器和CAS客户端都做了一些什么事,这些事
Easter79 Easter79
2年前
SSO单点登录基于CAS架构封装 Memcached 实例
SSO认证中心是CAS整个应用架构的一个极其重要的关键点,必须满足如下两点要求:1.高可用,不允许程序发生故障。如果认证中心发生故障,整个应用群将无法登录,导致所有服务瘫痪。2.高并发,因为所有用户的登录请求都需要经过它处理,其承担的处理量往往是相当巨大的。其中memcached的CAS源码MemCacheTicketRegistry.java类
Wesley13 Wesley13
2年前
CAS单点登录(一):单点登录与CAS理论介绍
一、什么是单点登录(SSO)  单点登录主要用于多系统集成,即在多个系统中,用户只需要到一个中央服务器登录一次即可访问这些系统中的任何一个,无须多次登录。  单点登录(SingleSignOn),简称为SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所
Easter79 Easter79
2年前
Springboot+CAS单点登录
一:安装CAS下载cas:https://github.com/apereo/cas(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fapereo%2Fcas)1.1 将cas并打成war包。放入一个干净的tomcat中,启动tomcat
Easter79 Easter79
2年前
SpringBoot项目集成cas单点登录
添加依赖添加casclient依赖<dependency<groupIdnet.unicon.cas</groupId<artifactIdcasclientautoconfigsupport</artifactId
Stella981 Stella981
2年前
SpringBoot项目集成cas单点登录
添加依赖添加casclient依赖<dependency<groupIdnet.unicon.cas</groupId<artifactIdcasclientautoconfigsupport</artifactId
Stella981 Stella981
2年前
SSO单点登录基于CAS架构封装 Memcached 实例
SSO认证中心是CAS整个应用架构的一个极其重要的关键点,必须满足如下两点要求:1.高可用,不允许程序发生故障。如果认证中心发生故障,整个应用群将无法登录,导致所有服务瘫痪。2.高并发,因为所有用户的登录请求都需要经过它处理,其承担的处理量往往是相当巨大的。其中memcached的CAS源码MemCacheTicketRegistry.java类
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k