jeesite整合单点登录

2023-11-05

1.什么是单点登录

单点登录SSOSingle Sign On)实际上就是用户在一个系统登录之后,在单点登录的其他客户端(应用)不用重复的登陆,登陆校验交给中央认证服务器去校验。单点登录的应用场景通常为一个大型的系统下有很多小系统,并且这些系统使用的是同一套认证体系。

常用的单点登录框架为cas,cas分为cas-server,cas-client.

2.使用jeesite实现单点登录的配置

看过jeesite的应该知道,jeesite使用的是shiro整合spring的方式,并且自定义实现了多种SessionManager和多种cacheManager,。由于单点登录的特殊性,需要我们自定义realmrealm可以看做是一个安全数据源,用来收集用户的认证信息和授权信息。

2.1单点登录的配置文件

2.1.1 loginUrl配置的为单点登录认证服务器的地址和service回调地址

2.1.2  需要单独配置logoutFilter,用于到认证服务器进行单点退出。

2.1.3 配置casFilter用于接收认证服务器验证之后的信息。并进行认证授权的处理

2.1.4自定义relam,在SystemAuthorizingRealm基础上进行改造。

2.1.5单点登录的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd"
	default-lazy-init="true">

	<description>Shiro Configuration</description>

	<!-- 加载配置属性文件 -->
	<context:property-placeholder
		ignore-unresolvable="true" location="classpath:app.properties" />

	<!-- Shiro权限过滤过滤器定义 -->
	<bean name="shiroFilterChainDefinitions" class="java.lang.String">
		<constructor-arg>
			<value>
				/static/** = anon
				/userfiles/** = anon
				${adminPath}/cas = cas
				<!-- ${adminPath}/login = authc -->
				${adminPath}/logout = logout
				${adminPath}/** = user
				/act/rest/service/editor/** = perms[act:model:edit]
				/act/rest/service/model/** = perms[act:model:edit]
				/act/rest/service/** = user
				/ReportServer/** = user
			</value>
		</constructor-arg>
	</bean>

	


	<!-- 安全认证过滤器 -->

	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<property name="loginUrl" value="${cas.server.url}/login?service=${cas.project.url}${adminPath}/cas" 
			/>
		<!-- <property name="loginUrl" value="${adminPath}/login" /> -->
		<property name="successUrl" value="${adminPath}/index?login" />
		<property name="filters">
			<map>
				<entry key="cas" value-ref="casFilter" />
				<entry key="logout">
					<bean class="org.apache.shiro.web.filter.authc.LogoutFilter">
						<property name="redirectUrl" value="${cas.server.url}/logout?service=${cas.project.url}${frontPath}"></property>
					</bean>
				</entry>
				<!-- <entry key="authc" value-ref="formAuthenticationFilter" /> -->
			</map>
		</property>
		<property name="filterChainDefinitions">
			<ref bean="shiroFilterChainDefinitions" />
		</property>
	</bean>
	<!-- CAS认证过滤器 -->
	<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
		<property name="failureUrl" value="${frontPath}/login" />
	</bean>

	<!-- 定义Shiro安全管理配置 -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="casAuthorizingRealm" />
		<property name="sessionManager" ref="sessionManager" />
		<property name="cacheManager" ref="shiroCacheManager" />
	</bean>
	
	
	<bean id="casAuthorizingRealm" class="com.aligns.administrator.sys.security.CasAuthorizingRealm">
	  	<property name="casServerUrlPrefix" value="${cas.server.url}" />
        <property name="casService" value="${cas.project.url}${adminPath}/cas" />
	</bean>

	<!-- 自定义会话管理配置 -->
	<bean id="sessionManager"
		class="com.aligns.plat.core.security.shiro.session.SessionManager">
		<property name="sessionDAO" ref="sessionDAO" />

		<!-- 会话超时时间,单位:毫秒 -->
		<property name="globalSessionTimeout" value="${session.sessionTimeout}" />

		<!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话 -->
		<property name="sessionValidationInterval" value="${session.sessionTimeoutClean}" />
		<!-- <property name="sessionValidationSchedulerEnabled" value="false"/> -->
		<property name="sessionValidationSchedulerEnabled" value="true" />

		<property name="sessionIdCookie" ref="sessionIdCookie" />
		<property name="sessionIdCookieEnabled" value="true" />
	</bean>

	<!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID, 
		当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! -->
	<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
		<constructor-arg name="name" value="jeesite.session.id" />
	</bean>

	<!-- 自定义Session存储容器 -->
<!-- 	<bean id="sessionDAO" class="com.thinkgem.jeesite.common.security.shiro.session.JedisSessionDAO">
		<property name="sessionIdGenerator" ref="idGen" />
		<property name="sessionKeyPrefix" value="${redis.keyPrefix}_session_" />
	</bean> -->
	
	<bean id="sessionDAO"
		class="com.aligns.plat.core.security.shiro.session.CacheSessionDAO">
		<property name="sessionIdGenerator" ref="idGen" />
		<property name="activeSessionsCacheName" value="activeSessionsCache" />
		<property name="cacheManager" ref="jedisCacheManager" />
	</bean>
	 
	 
	 
	 <!-- 
	 <bean id="jedisUtils" class="com.aligns.plat.utils.JedisUtils"></bean>
	 -->
	 <!-- 如果需要集群配置,则将SessionDao设置为jedis -->
	 
<!-- 	<bean id="sessionDAO"
		class="com.aligns.plat.core.security.shiro.session.JedisSessionDAO" >
		<property name="sessionIdGenerator" ref="idGen" />
		<property name="activeSessionsCacheName" value="activeSessionsCache" />
		<property name="cacheManager" ref="jedisCacheManager" />
		
	</bean> -->
	
	
	
	
	
	

	<!-- 定义授权缓存管理器 -->
	<!-- <bean id="shiroCacheManager" class="com.aligns.plat.core.common.security.shiro.cache.SessionCacheManager" 
		/> -->
	<bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
		<property name="cacheManager" ref="cacheManager" />
	</bean>
	
	
	<bean id="jedisCacheManager" class="com.aligns.plat.core.security.shiro.cache.JedisCacheManager">
		
	</bean>

	<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

	<!-- AOP式方法级权限检查 -->
	<bean
		class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
		depends-on="lifecycleBeanPostProcessor">
		<property name="proxyTargetClass" value="true" />
	</bean>
	<bean
		class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />
	</bean>

</beans>

2.1.6单点登录的自定义relam(CasAuthorizingRealm)

/**
 * 
 */
package com.aligns.administrator.sys.security;

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

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cas.CasAuthenticationException;
import org.apache.shiro.cas.CasRealm;
import org.apache.shiro.cas.CasToken;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.util.StringUtils;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.jasig.cas.client.validation.TicketValidationException;
import org.jasig.cas.client.validation.TicketValidator;

import com.aligns.administrator.sys.entity.Menu;
import com.aligns.administrator.sys.entity.Role;
import com.aligns.administrator.sys.entity.User;
import com.aligns.administrator.sys.security.SystemAuthorizingRealm.Principal;
import com.aligns.administrator.sys.service.SystemService;
import com.aligns.administrator.sys.utils.LogUtils;
import com.aligns.administrator.sys.utils.UserUtils;
import com.aligns.plat.core.Servlets;
import com.aligns.plat.utils.SpringContextHolder;

/**
 * 系统安全认证单点登录实现类
 * 
 * @author kefan
 * @version 2014-7-5
 */
//@Service
// @DependsOn({"userDao","roleDao","menuDao"})
public class CasAuthorizingRealm extends CasRealm {
	private SystemService systemService;
	 
    public CasAuthorizingRealm() {  
        super();  
    }

    /**
     * 认证
     * */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {  
        CasToken casToken = (CasToken) token;  
        if (token == null)  
            return null;  
        String ticket = (String) casToken.getCredentials();  
        if (!StringUtils.hasText(ticket))  
            return null;  
        TicketValidator ticketValidator = ensureTicketValidator();  
        try {  
            Assertion casAssertion = ticketValidator.validate(ticket, getCasService());  
            //casPrincipal  认证后的用户信息
            AttributePrincipal casPrincipal = casAssertion.getPrincipal();  
            String userId = casPrincipal.getName();  
            
            //获取用户
            User user = getSystemService().getUserByLoginName(userId);
            
            Map<String,Object> attributes = casPrincipal.getAttributes();  
            casToken.setUserId(userId);  
            String rememberMeAttributeName = getRememberMeAttributeName();  
            String rememberMeStringValue = (String) attributes.get(rememberMeAttributeName);  
            boolean isRemembered = rememberMeStringValue != null && Boolean.parseBoolean(rememberMeStringValue);  
            if (isRemembered)  
                casToken.setRememberMe(true);  
            // 这里可以拿到Cas的登录账号信息,加载到对应权限体系信息放到缓存中...  
            return new SimpleAuthenticationInfo(new Principal(user, false), ticket,getName());  
        } catch (TicketValidationException e) {  
            throw new CasAuthenticationException((new StringBuilder()).append("Unable to validate ticket [")  
                    .append(ticket).append("]").toString(), e);  
        }  
    }  
    
    /**
     * 授权
     * */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    	Principal principal = (Principal) getAvailablePrincipal(principals);
		
		
    	User user = getSystemService().getUserByLoginName(principal.getLoginName());
		if (user != null) {
			SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
			List<Menu> list = UserUtils.getMenuList();
			for (Menu menu : list){
				if (org.apache.commons.lang3.StringUtils.isNotBlank(menu.getPermission())){
					// 添加基于Permission的权限信息
					for (String permission : org.apache.commons.lang3.StringUtils.split(menu.getPermission(),",")){
						info.addStringPermission(permission);
					}
				}
			}
			// 添加用户权限
			info.addStringPermission("user");
			// 添加用户角色信息
			for (Role role : user.getRoleList()){
				info.addRole(role.getEnname());
			}
			// 更新登录IP和时间
			getSystemService().updateUserLoginInfo(user);
			// 记录登录日志
			LogUtils.saveLog(Servlets.getRequest(), "系统登录");
			return info;
		} else {
			return null;
		}
	
    }  
  
    protected List<String> split(String s) {  
        List<String> list = new ArrayList<String>();  
        String elements[] = StringUtils.split(s, ',');  
        if (elements != null && elements.length > 0) {  
            String arr$[] = elements;  
            int len$ = arr$.length;  
            for (int i$ = 0; i$ < len$; i$++) {  
                String element = arr$[i$];  
                if (StringUtils.hasText(element))  
                    list.add(element.trim());  
            }  
  
        }  
        return list;  
    }  
  
    protected void addRoles(SimpleAuthorizationInfo simpleAuthorizationInfo, List<String> roles) {  
        String role;  
        for (Iterator<String> i$ = roles.iterator(); i$.hasNext(); simpleAuthorizationInfo.addRole(role))  
            role = (String) i$.next();  
  
    }  
  
    protected void addPermissions(SimpleAuthorizationInfo simpleAuthorizationInfo, List<String> permissions) {  
        String permission;  
        for (Iterator<String> i$ = permissions.iterator(); i$.hasNext(); simpleAuthorizationInfo  
                .addStringPermission(permission))  
            permission = (String) i$.next();  
  
    }  
    
	public SystemService getSystemService() {
		if (systemService == null){
			systemService = SpringContextHolder.getBean(SystemService.class);
		}
		return systemService;
	}
}

3.需要注意的事项:

配置文件中配置的logout,为logoutFilter,redirectUrl为认证服务器注销之后的重定向地址,单点登录需要配置用于注销重定向,否则注销之后,页面会停留在单点登录服务器,不会调到我们自己的应用。修改认证服务器的cas-servlet,路径为WEB-INF/cas-servet.xml,把false改为true





本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

jeesite整合单点登录 的相关文章

  • 表白墙程序

    目录 一 页面代码部分 二 设计程序 二 实现 doPost 编辑 三 实现 doGet 四 前端代码部分 五 使用数据库存储数据 一 页面代码部分 在之前的一篇博客中 已经写过了表白墙的页面代码实现 这里就不再重复了 页面代码如下 div
  • 使用阿里巴巴的EasyExcel操作Excel

    引入依赖
  • java中CompletableFuture异步编程详解以及实践案例

    文章目录 一 CompletableFuture的使用 1 创建CompletableFuture的方式 2 获得异步执行结果 3 对执行结果进行处理 4 对执行结果进行消费 5 异常处理 6 两组任务按顺序执行 7 两组任务谁快用谁 8
  • 使用 Linux 相关知识部署博客系统

    目录 编辑一 认识 Linux 二 如何拥有 Linux 环境 三 常见的 Linux 命令 1 目录相关命令 1 ls 2 pwd 3 cd 2 文件操作相关命令 1 touch 2 cat 3 echo 3 vim vim 的关键概念
  • 详解JAVA远程debug

    目录 1 什么是远程debug 2 远程debug普通JAVA程序 环境 测试程序 程序启动指令 编译器配置 3 远程debug JAVA Web程序 4 远程debug spring boot程序 1 什么是远程debug 远程debug
  • 用struts框架+正则表达式对数据进行校验

    创建文件名为XXX xxx validation xml XXX为Action类名 xxx为struct xml中对应的action配置的name名 并和该类放在同一个包中 校验文件部分代码如下 非字段型校验器
  • 网络原理详解(图文结合)

    目录 编辑一 应用层 1 请求和响应 2 通用的协议格式 1 xml 2 json 3 protobuffer 二 传输层 1 UDP 2 TCP 1 TCP 协议段格式 2 可靠传输的实现机制 确认应答机制 可靠性 超时重传机制 可靠性
  • Caused by:org.springframework.beans.factory.NoSuchBeanDefinitionException:No qualifying bean of type

    今天使用Junit单元测试写了个测试spring的AnnotationConfigApplicationContext 的测试方法 代码如下 public class TestApplicationContext Test 较为经典的容器
  • 黑马程序员Spring视频教程,全面深度讲解spring5底层原理 学习笔记

    介绍 代码仓库地址 https gitee com CandyWall spring source study 跟着黑马满一航老师的spring高级49讲做的学习笔记 本笔记跟视频内容的项目名称和代码略有不同 我将49讲的代码每一讲的代码都
  • JPA常用注解

    JPA全称Java Persistence API JPA通过JDK 5 0注解或XML描述对象 关系表的映射关系 并将运行期的实体对象持久化到数据库中 JPA由EJB 3 0软件专家组开发 作为JSR 220实现的一部分 但它不囿于EJB
  • Java EE 企业级应用 复习 Spring中Bean的管理

    Bean的实例化 什么是Bean的实例化 Spring容器自动地帮助我们生成对应的Bean对象 Bean的实例化方法 构造方法实例化 静态工厂实例化 实例工厂实例化 构造方法实例化 package com itheima public cl
  • Servlet学习——为什么在web容器中servlet对象只有一个?

    以下为本人个人观点 如有错误 望指出 不胜感激 简单来说就是为了节省内存 servlet的设计非常的巧妙 如果我们对每一个用户请求都生成一个对应servlet的对象 第一 由于web服务器的访问量比较大 意味着内存开销会很大 第二 要GC大
  • 【Spring Boot】详解restful api

    目录 1 restful api 1 1 历史 1 2 内容 1 3 传参 2 Spring Boot中的Restful Api 1 restful api 1 1 历史 RESTful API Representational State
  • 初识网络原理(笔记)

    目录 编辑局域网 网络通信基础 IP 地址 端口号 协议 协议分层 TCP IP 五层网络模型 网络数据传输的基本流程 发送方的情况 接收方的情况 局域网 搭建网络的时候 需要用到 交换机 和 路由器 路由器上 有 lan 口 和 wan
  • Netty4之编解码

    本文是基于Netty4 1 x 一般在使用Netty作为网络框架进行开发时 编解码框架是我们应该注意的一个重要部分 应用从网络层接收数据需要经过解码 Decode 将二进制的数据报转换从应用层的协议消息 这样才能被应用逻辑所识别 同样 客户
  • Vue.js怎么给文本域赋默认值,和获取输入的值

    Vue js怎么给文本域赋默认值 一般给文本域赋初值用于修改某个东西 需要获取默认值 可以用v model来完成
  • 14.应用层HTTP协议

    目录 一 OSI七层协议 vs TCP IP五层协议 二 HTTP协议 URL 1 1URL 中的可省略部分 2 请求消息Request 2 1请求行 2 2请求头 2 3空行 2 4请求数据 2 5HTTP 请求方法 3 响应消息Resp
  • Map和String的相互转化

    Java中的Map集合与String的相互转化 代码如下 package com jianhu Test import java util Arrays import java util HashMap import java util M
  • Spring AOP、拦截器、过滤器的区别

    一 区别与概念 Filter过滤器 拦截web访问url地址 Interceptor拦截器 拦截以 action结尾的url 拦截Action的访问 Spring AOP拦截器 只能拦截Spring管理Bean的访问 业务层Service
  • JSTL 教程、JSTL 标签示例

    JSTL 代表JSP 标准标签库 JSTL 是标准标记库 它提供标记来控制 JSP 页面行为 JSTL 标签可用于迭代和控制语句 国际化 SQL 等 我们将在本 JSTL 教程中详细研究 JSTL 标签 之前我们看到了如何使用JSP EL

随机推荐

  • java理论知识浙大_java 理论知识(-)

    关键字和保留字区别 关键字 keyword 表示一种数据类型 或者表示程序的结构等 保留字 reserved word 为java预留的关键字 以后的升级版本中可能作为关键字 支持概念 1 多态 2 继承 3 封装 4 抽象 5 类 6 对
  • deep learning: deep feedforward network (output and hidden layer)

    deep forward networks feedforward neural networks multiplayer perceptrons MLP input layer hidden layer output layer acti
  • rpm 安装时提示缺少依赖库

    在麒麟系统下安装ecryptfs utils 82 6 ky3 3 x86 64 rpm 该软件包在 麒麟光盘的 KYLIN目录下 使用如下命令 rpm ivh ecryptfs utils 82 6 ky3 3 x86 64 rpm 提示
  • 循环数组有几种方法?

    第一种 普通for循环 for i 0 i
  • H3C交换机SSH配置举例

    注 本文仅供个人学习参考 禁止用作商业用途 因他人转载产生纠纷 本人不承担任何责任 password认证配置举例 1 组网需求 如图 配置Host SSH客户端 与Switch建立本地连接 Host采用SSH协议登录到Switch上 以保证
  • Unity3d--实现太阳系仿真

    一 实验要求 写一个程序 实现一个完整的太阳系 其他星球围绕太阳的转速必须不一样 且不在一个法平面上 二 实验过程 创建如下结构 solar 里包括太阳和8大行星 并且设置好距离和大小 在网上找到相应贴图 添加到assets 将贴图拖动到对
  • Vue中的侦听器:数据变化的秘密揭示

    一 侦听器 vue中想监听数据的变化 一 侦听器watch 如何侦听到某个变量值改变呢 使用watch配置项 watch 可以侦听到data computed属性值的改变 语法 watch 被侦听的属性名 newVal oldVal 快速入
  • 2021全国职业技能大赛-网络安全赛题解析———防火墙篇iptables(超详细)

    2021全国职业技能大赛 网络安全赛题解析 防火墙篇 模块A防火墙的基本规则操作 什么是防火墙 iptables 有问题私信博主 模块A防火墙的基本规则操作 什么是防火墙 iptables IPTABLES 是与最新的 3 5 版本 Lin
  • 2021Robocom决赛---账户安全预警

    拼题 A 系统为提高用户账户的安全性 打算开发一个自动安全预警的功能 对每个账户的每次登录 系统会记录其登录的 IP 地址 每隔一段时间 系统将统计每个账户从多少不同的 IP 地址分别登录了多少次 如果某个账户的登录 IP 超过了 TIP
  • Python如何将字符串(str/json)转换字典(dict)

    一 字符串str转为字典dict 1 使用json进行转换 import json a a 1 b 1 c json loads a print c type c 输出 a 1 c 1
  • GraphQL 中文 -- 一份不标准不专业的翻译

    请移步我的 Github 查看翻译 如有翻译不恰当的地方欢迎指正
  • python 实现GUI(图形用户界面)编程

    Python支持多种图形界面的第三方库 包括 wxWidgets Qt GTK Tkinter Tkinter 模块 Tk 接口 是 Python 的标准 Tk GUI 工具包的接口 Tk 和 Tkinter 可以在大多数的 Unix 平台
  • Springboot整合Swagger2(3.0.0版本)

    天行健 君子以自强不息 地势坤 君子以厚德载物 每个人都有惰性 但不断学习是好好生活的根本 共勉 文章均为学习整理笔记 分享记录为主 如有错误请指正 共同学习进步 文章目录 Swagger2简介 开发环境 实现步骤说明 1 搭建项目 2 引
  • JxBrowser Java浏览器控件

    关键字 JxBrowser能在Windows Linux Mac OS X Intel and PPC based 平台上将Mozilla Firefox浏览器完美地整合到Java AWT Swing应用程序里 该库程序使用Gecko设计引
  • win7/win10电脑屏幕录像工具?

    目前windows系统中 windows 7系统是没有自带的录屏软件 windows 10系统也是对电脑型号有要求 所以在录屏的时候 就需要通过其他三方工具去处理 下载安装 一款优质录屏软件可以给我们的工作以及生活带来不少的便捷 QVE屏幕
  • linux 查看定时任务

    输入cd var spool cron命令 输入ls命令列出cron目录下的定时任务 vi 查看
  • 强制tensorflow使用cpu

    one start import tensorflow as tf cpu tf config list physical devices CPU tf config set visible devices cpu print tf con
  • Java 中SimpleDateFormat类的使用

    博主前些天发现了一个巨牛的人工智能学习网站 通俗易懂 风趣幽默 忍不住也分享一下给大家 点击跳转到网站 SimpleDateFormat类的介绍 SimpleDateFormat类是一个具体的类 用于以区域设置敏感的方式格式化和解析日期 日
  • VirtualAPK 详解和使用,真牛

    3 1 基本原理 合并宿主和插件的ClassLoader 需要注意的是 插件中的类不可以和宿主重复 合并插件和宿主的资源 重设插件资源的packageId 将插件资源和宿主资源合并 去除插件包对宿主的引用 构建时通过Gradle插件去除插件
  • jeesite整合单点登录

    1 什么是单点登录 单点登录SSO Single Sign On 实际上就是用户在一个系统登录之后 在单点登录的其他客户端 应用 不用重复的登陆 登陆校验交给中央认证服务器去校验 单点登录的应用场景通常为一个大型的系统下有很多小系统 并且这