若依微服务集成CAS,实现单点登录

这篇具有很好参考价值的文章主要介绍了若依微服务集成CAS,实现单点登录。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

若依(RuoYi)微服务是一款基于Spring Cloud Alibaba开发的企业级微服务框架,采用前后端分离方式,使用了常用的微服务组件,如Feign、Nacos、Sentinel、Seata等,提供了丰富的微服务治理功能,如服务注册、发现、路由、负载均衡、熔断降级、限流等。借助若依微服务框架可以让我们快速构建起一个高效、可靠、可扩展的分布式系统,提高了开发效率和系统性能。

借助Spring Cloud Alibaba,若依微服务框架完成了后端的微服务改造,但是前端仍是一个单体服务,随着业务的增长,前端必然变的庞大、臃肿,不可避免的需要对前端进行拆分,然而前端拆分后面临的一个问题是登录信息如何同步?登录信息是以token存储在cookie中的,无法共享。

为了解决前端登录信息同步的问题,这里考虑通过集成CAS的方式,实现统一认证。

研究了若依微服务的认证功能后发现,若依微服务的认证并未使用Spring Security,仅仅使用了Spring Security的加密功能,无法直接套用若依分离版集成CAS的方式。所以通过结合分离版集成思路及CAS官方集成方法完成若依微服务集成CAS。集成方法如下:

1、添加CAS依赖

在auth模块中添加cas依赖:

<!-- Cas Core -->
<dependency>
  <groupId>org.jasig.cas.client</groupId>
  <artifactId>cas-client-core</artifactId>
  <version>3.6.4</version>
</dependency>

2、修改配置文件

在nacos中修改ruoyi-auth-dev.yml(或直接修改auth模块下bootstrap.yml文件),增加cas配置:

cas:
  enable: true
  server:
    url:
      prefix: http://127.0.0.1:8888/cas
      login: http://127.0.0.1:8888/cas/login
  client:
    url: http://127.0.0.1:8080/auth

3、修改Constants.java

修改common-core模块下
com.ruoyi.common.core.constant.Constants.java,增加CAS认证成功标识:

/**
 * CAS登录成功后的后台标识
 **/
public static final String CAS_TOKEN = "cas_token";

/**
 * CAS登录成功后的前台Cookie的Key
 **/
public static final String WEB_TOKEN_KEY = "Cloud-Token";

/**
 * CAS登录成功后的前台Cookie的Expires-In
 **/
public static final String WEB_TOKEN_EXPIRES = "Cloud-Expires-In";

4、添加CasProperties.java

在auth模块中添加CasProperties.java文件,获取CAS配置信息:

package com.ruoyi.auth.cas.config.properties;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;

/**
 * @author LuoFei
 * @className: CasProperty
 * @projectName RuoYi-Cloud-master
 * @description: cas配置参数
 * @date 2022/7/21 10:11
 **/
@Configuration
@RefreshScope
public class CasProperties {

    @Value("${cas.enable}")
    private Boolean enabled;

    @Value("${cas.server.url.prefix}")
    private String casServerUrlPrefix;

    @Value("${cas.server.url.login}")
    private String casServerLoginUrl;

    @Value("${cas.client.url}")
    private String serverName;

    public Boolean getEnabled() {
        return enabled;
    }

    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }

    public String getCasServerUrlPrefix() {
        return casServerUrlPrefix;
    }

    public void setCasServerUrlPrefix(String casServerUrlPrefix) {
        this.casServerUrlPrefix = casServerUrlPrefix;
    }

    public String getCasServerLoginUrl() {
        return casServerLoginUrl;
    }

    public void setCasServerLoginUrl(String casServerLoginUrl) {
        this.casServerLoginUrl = casServerLoginUrl;
    }

    public String getServerName() {
        return serverName;
    }

    public void setServerName(String serverName) {
        this.serverName = serverName;
    }
}

5、添加NoCasFilter.java

在auth模块中添加NoCasFilter.java文件,在未启用CAS时直接放行:

package com.ruoyi.auth.cas.filter;

import javax.servlet.*;
import java.io.IOException;

/**
 * @author LuoFei
 * @className: NoCasFilter
 * @projectName RuoYi-Cloud-master
 * @description: 单点登录停用辅助过滤器
 * @date 2022/7/21 11:19
 **/
public final class NoCasFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        filterChain.doFilter(request, response);
    }
}

6、 添加
CustomSessionMappingStorage.java

在auth模块中添加
CustomSessionMappingStorage.java文件,实现单点登出:

package com.ruoyi.auth.cas.storage;

import com.ruoyi.common.core.constant.Constants;
import com.ruoyi.common.security.service.TokenService;
import org.apache.catalina.session.StandardSessionFacade;
import org.jasig.cas.client.session.SessionMappingStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.Map;

/**
 * @author LuoFei
 * @className: CustomSessionMappingStorage
 * @projectName RuoYi-Vue-master
 * @description: 单点登录-前后端分离-单点登出删除token
 * @date 2022/4/28 12:56
 **/
@Component
public class CustomSessionMappingStorage implements SessionMappingStorage {
    private final Map<String, HttpSession> MANAGED_SESSIONS = new HashMap();
    private final Map<String, String> ID_TO_SESSION_KEY_MAPPING = new HashMap();
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private TokenService tokenService;

    public CustomSessionMappingStorage() {
    }

    @Override
    public synchronized void addSessionById(String mappingId, HttpSession session) {
        this.ID_TO_SESSION_KEY_MAPPING.put(session.getId(), mappingId);
        this.MANAGED_SESSIONS.put(mappingId, session);
    }

    @Override
    public synchronized void removeBySessionById(String sessionId) {
        this.logger.debug("Attempting to remove Session=[{}]", sessionId);
        String key = (String)this.ID_TO_SESSION_KEY_MAPPING.get(sessionId);
        if (this.logger.isDebugEnabled()) {
            if (key != null) {
                this.logger.debug("Found mapping for session.  Session Removed.");
            } else {
                this.logger.debug("No mapping for session found.  Ignoring.");
            }
        }

        this.MANAGED_SESSIONS.remove(key);
        this.ID_TO_SESSION_KEY_MAPPING.remove(sessionId);
    }

    @Override
    public synchronized HttpSession removeSessionByMappingId(String mappingId) {
        StandardSessionFacade session = (StandardSessionFacade) this.MANAGED_SESSIONS.get(mappingId);
        if (session != null) {
            this.removeBySessionById(session.getId());
            try {
                String token = (String) session.getAttribute(Constants.CAS_TOKEN);
                tokenService.delLoginUser(token);
            } catch (IllegalStateException e) {
                this.logger.error("已成功登出");
            }
        }
        return session;
    }
}

7、增加casLogin方法

在auth模块的TokenController.java文件中添加casLogin方法,实现登录功能:

/**
 * 单点登录成功创建token
 * @param request
 * @param response
 * @throws IOException
 * @throws ServletException
 **/
@GetMapping("casLogin")
public void casLogin(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
    String username = request.getRemoteUser();
    HttpSession httpSession = request.getSession();

    String url = request.getParameter("redirect");
    LoginUser userInfo = sysLoginService.login(username);
    Map<String, Object> token = tokenService.createToken(userInfo);

    Cookie tokenCookie = new Cookie(Constants.WEB_TOKEN_KEY, (String) token.get("access_token"));
    //必须设置path,否则获取不到cookie
    tokenCookie.setPath("/");
    response.addCookie(tokenCookie);
    Cookie expiresCookie = new Cookie(Constants.WEB_TOKEN_EXPIRES, ((Long) token.get("expires_in")).toString());
    expiresCookie.setPath("/");
    response.addCookie(expiresCookie);
    //设置后端认证成功标识

    httpSession.setAttribute(Constants.CAS_TOKEN, token.get("access_token"));
    //登录成功后跳转到前端访问页面
    response.sendRedirect(url);
}

8、添加CasConfig.java文件

在auth模块中添加CasConfig.java文件:

package com.ruoyi.auth.cas.config;

import com.ruoyi.auth.cas.config.properties.CasProperties;
import com.ruoyi.auth.cas.filter.NoCasFilter;
import com.ruoyi.auth.cas.storage.CustomSessionMappingStorage;
import org.jasig.cas.client.authentication.AuthenticationFilter;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author LuoFei
 * @className: CasConfig
 * @projectName RuoYi-Cloud-master
 * @description: TODO
 * @date 2022/7/19 14:17
 **/
@Configuration
public class CasConfig {

    @Autowired
    private CasProperties casProperties;

    @Autowired
    private CustomSessionMappingStorage customSessionMappingStorage;

    /**
     * 单点登出过滤器
     * @return
     **/
    @Bean
    public FilterRegistrationBean logoutFilter() {
        FilterRegistrationBean authenticationFilter = new FilterRegistrationBean<>();
        SingleSignOutFilter signOutFilter = new SingleSignOutFilter();
        signOutFilter.setSessionMappingStorage(customSessionMappingStorage);
        signOutFilter.setIgnoreInitConfiguration(true);
        authenticationFilter.setFilter(signOutFilter);
        authenticationFilter.addUrlPatterns("/*");
        Map<String, String> initParameters = new HashMap<>();
        initParameters.put("casServerUrlPrefix", casProperties.getCasServerUrlPrefix());
        authenticationFilter.setInitParameters(initParameters);
        authenticationFilter.setOrder(1);
        if (casProperties.getEnabled()) {
            return authenticationFilter;
        }
        return new FilterRegistrationBean<>(new NoCasFilter());
    }

    /**
     * 单点登录认证入口
     * @return
     **/
    @Bean
    public FilterRegistrationBean authenticationFilterRegistrationBean() {
        FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
        authenticationFilter.setFilter(new AuthenticationFilter());
        Map<String, String> initParameters = new HashMap<>();
        initParameters.put("casServerLoginUrl", casProperties.getCasServerLoginUrl());
        initParameters.put("serverName", casProperties.getServerName());
        authenticationFilter.setInitParameters(initParameters);
        authenticationFilter.setOrder(2);
        List<String> urlPatterns = new ArrayList<>();
        urlPatterns.add("/casLogin");
        authenticationFilter.setUrlPatterns(urlPatterns);
        if (casProperties.getEnabled()) {
            return authenticationFilter;
        }
        return new FilterRegistrationBean<>(new NoCasFilter());
    }

    /**
     * 单点登录验证入口
     * @return
     **/
    @Bean
    public FilterRegistrationBean validationFilterRegistrationBean() {
        FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
        authenticationFilter.setFilter(new Cas20ProxyReceivingTicketValidationFilter());
        Map<String, String> initParameters = new HashMap<>();
        initParameters.put("casServerUrlPrefix", casProperties.getCasServerUrlPrefix());
        initParameters.put("serverName", casProperties.getServerName());
        initParameters.put("encoding", "UTF-8");
        initParameters.put("useSession", "true");
        authenticationFilter.setInitParameters(initParameters);
        authenticationFilter.setOrder(3);
        List<String> urlPatterns = new ArrayList<>();
        urlPatterns.add("/*");
        authenticationFilter.setUrlPatterns(urlPatterns);
        if (casProperties.getEnabled()) {
            return authenticationFilter;
        }
        return new FilterRegistrationBean<>(new NoCasFilter());
    }

    /**
     * 单点登录获取登录信息
     * @return
     **/
    @Bean
    public FilterRegistrationBean casHttpServletRequestWrapperFilter() {
        FilterRegistrationBean authenticationFilter = new FilterRegistrationBean();
        authenticationFilter.setFilter(new HttpServletRequestWrapperFilter());
        authenticationFilter.setOrder(4);
        List<String> urlPatterns = new ArrayList<>();
        urlPatterns.add("/*");
        authenticationFilter.setUrlPatterns(urlPatterns);
        if (casProperties.getEnabled()) {
            return authenticationFilter;
        }
        return new FilterRegistrationBean<>(new NoCasFilter());
    }
}

9、放行casLogin请求

修改common-security模块中的WebMvcConfig.java,放行casLogin请求:

/** 不需要拦截地址 **/
public static final String[] excludeUrls = { "/casLogin", "/login", "/logout", "/refresh", "/register" };

修改nacos中ruoyi-gateway-dev.yml,在网关中放行casLogin请求:

# 不校验白名单
  ignore:
    whites:
      - /auth/casLogin
      - /auth/getToken
      - /auth/logout
      - /auth/login
      - /auth/register
      - /auth/updatePassword
      - /*/v2/api-docs
      - /csrf

至此,即完成若依微服务后端CAS集成工作。

若依微服务前端集成与分离版相同,请参考若依分离版集成CAS。文章来源地址https://www.toymoban.com/news/detail-653277.html

到了这里,关于若依微服务集成CAS,实现单点登录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【SpringBoot】集成SpringSecurity+JWT实现多服务单点登录,原来这么easy

    Spring Boot+Spring Security+JWT实现单点登录 介绍: 单点登录(SingleSignOn,SSO) ,当用户在身份 认证服务器 上登录一次以后,即可 获得访问单点登录系统中其他关联系统和应用软件的权限 ,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用

    2024年02月02日
    浏览(29)
  • 单点登录:CAS使用springboot main方法启动cas-server

    1.下载demo 2.使用eclipse导入maven项目。此次我是用的spring tool suite 4导入的。 导入时会用较长时间,10分钟吧。需要下载很多资源。 3.报错,提示缺少jar包 4.其他地方下载该jar包。我是在cas-server-webapp-tomcat-5.3.9.war中解压中找到xmlsectool-2.0.0.jar。 5.安装jar。 6.更新项目。 pom.xml右键

    2024年02月09日
    浏览(45)
  • 【实践篇】基于CAS的单点登录实践之路

    作者:京东物流 赵勇萍 上个月我负责的系统SSO升级,对接京东ERP系统,这也让我想起了之前我做过一个单点登录的项目。想来单点登录有很多实现方案,不过最主流的还是基于CAS的方案,所以我也就分享一下我的CAS实践之路。 单点登录的英文名叫做:Single Sign On(简称SSO)

    2023年04月13日
    浏览(56)
  • 开源单点登录MaxKey和JeeSite 单点登录集成指南

    1. JeeSite介绍 JeeSite 隶属于济南卓源软件有限公司,是一个 Java 快速开发平台, 基于经典技术组合(Spring Boot、Shiro、MyBatis、Beetl+Bootstrap or TS+Vue3)在线代码生成工具, 支持 Spring Cloud 架构,分布式,微服务,微内核,企业、市政、信息化领域的专家。 支持国产化软硬件。 官

    2024年02月09日
    浏览(34)
  • 【钉钉免登录】使用dingtalk-jsapi将H5/小程序集成到钉钉,实现单点登录,H5/小程序免登

    一、创建H5微应用/小程序 1.1、创建微应用 登录钉钉开发者后台: 钉钉开发者后台 创建H5微应用:应用开发-企也内部-钉钉应用-创建应用 填写应用名称和应用描述 1.2 查看配置信息 1.3 配置服务器出口IP和应用首页地址 二、免登实现(小程序、H5均可用) 2.1 安装钉钉API 在终端

    2024年02月10日
    浏览(33)
  • 基于flask-oidc的OIDC协议授权码模式单点登录SSO实现

    关于SSO单点登录、OIDC协议、授权码模式等相关概念详见基于OIDC的SSO单点登录文章内容 应用注册: 在提供OIDC服务的认证系统中注册应用信息 授权流程: 携带由应用生成的 state (防CSRF跨域信息)和在认证系统中注册的应用信息重定向请求认证系统的授权服务 授权服务重定向到登

    2024年02月13日
    浏览(57)
  • 若依微服务版本集成积木报表

    新建报表微服务模块,这是我的项目结构图。 运行积木报表的初始化脚本,创建相关表结构,github速度太慢,推荐使用 gitee地址。选择你要建表的数据库,我是跟业务库放到了一起,执行完后会新增以下这几张表。 在顶级父pom中声明积木报表的版本号: 在报表微服务模块添

    2024年02月11日
    浏览(24)
  • 单点登陆(SSO)基于CAS实现前后端分离的SSO系统开发「IDP发起」

    关于其他前端常见登录实现+单点登录方案,请见「前端常见登录实现方案 + 单点登录方案 」 单点登录(SSO),英文全称为 Single Sign On。 SSO 是指在多个应用系统中,用户只需要登录一次,就可以访问所有相互信任的应用系统。 一般同域的SSO,用共享session就可以实现了,常见

    2024年01月25日
    浏览(37)
  • 9.Vue前端使用iframe集成帆软报表的单点登录

    一、背景 需要把帆软报表内嵌到若依里面来。 二、帆软设置 2.1 帆软报表的url 打开帆软后端里面的【目录管理】查看具体报表的url 帆软报表的具体地址为: Frm聚合报表地址: 【帆软的服务http】+【/webroot/decision/view/form?viewlet=demo/demo.frm】 CPT普通报表的地址:【帆软的服务ht

    2024年01月25日
    浏览(29)
  • 【Oauth2.0 单点登录 + 第三方授权认证】用户认证、授权模式

    本文主要对 SpringSecurity Oauth 2.0 用户认证,授权码授权模式、密码授权模式,以及授权流程进行讲解 开发中,有些功能只有管理员才有,普通用户是没有的。即需要对用户的身份进行认证,是管理员还是普通用户。认证方式有两种: 身份认证: 用户在访问相应资源时对用户

    2023年04月08日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包