收藏了一张很好的图,解释单点登录

上图是CAS官网上的标准流程,具体流程如下: 用户访问app系统,app系统是需要登录的,但用户现在没有登录。 跳转到CAS server,即SSO登录系统,以后图中的CAS Server我们统一叫做SSO系统。 SSO系统也没有登录,弹出用户登录页。 用户填写用户名、密码,SSO系统进行认证后,将登录状态写入SSO的session,浏览器(Browser)中写入SSO域下的Cookie。 SSO系统登录完成后会生成一个ST(Service Ticket),然后跳转到app系统,同时将ST作为参数传递给app系统。 app系统拿到ST后,从后台向SSO发送请求,验证ST是否有效。 验证通过后,app系统将登录状态写入session并设置app域下的Cookie。 至此,跨域单点登录就完成了。以后我们再访问app系统时,app就是登录的。接下来,我们再看看访问app2系统时的流程。 用户访问app2系统,app2系统没有登录,跳转到SSO。 由于SSO已经登录了,不需要重新登录认证。 SSO生成ST,浏览器跳转到app2系统,并将ST作为参数传递给app2。 app2拿到ST,后台访问SSO,验证ST是否有效。 验证成功后,app2将登录状态写入session,并在app2域下写入Cookie。 这样,app2系统不需要走登录流程,就已经是登录了。SSO,app和app2在不同的域,它们之间的session不共享也是没问题的。 有的同学问我,SSO系统登录后,跳回原业务系统时,带了个参数ST,业务系统还要拿ST再次访问SSO进行验证,觉得这个步骤有点多余。他想SSO登录认证通过后,通过回调地址将用户信息返回给原业务系统,原业务系统直接设置登录状态,这样流程简单,也完成了登录,不是很好吗? 其实这样问题时很严重的,如果我在SSO没有登录,而是直接在浏览器中敲入回调的地址,并带上伪造的用户信息,是不是业务系统也认为登录了呢?这是很可怕的。 总结 单点登录(SSO)的所有流程都介绍完了,原理大家都清楚了。总结一下单点登录要做的事情: 单点登录(SSO系统)是保障各业务系统的用户资源的安全 。 各个业务系统获得的信息是,这个用户能不能访问我的资源。 单点登录,资源都在各个业务系统这边,不在SSO那一方。 用户在给SSO服务器提供了用户名密码后,作为业务系统并不知道这件事。 SSO随便给业务系统一个ST,那么业务系统是不能确定这个ST是用户伪造的,还是真的有效,所以要拿着这个ST去SSO服务器再问一下,这个用户给我的ST是否有效,是有效的我才能让这个用户访问。

May 26, 2022 · 1 min · Rufus

分布式事务场景解决方案

分布式事务解决方案 要开始实现分布式事务,我们得先从理论上开始下手,我们来了解一下常用的分布式事务解决方案。 XA分布式事务协议 - 2PC(两阶段提交实现) 这里的PC实际上指的是Prepare和Commit,也就是说它分为两个阶段,一个是准备一个是提交,整个过程的参与者一共有两个角色,一个是事务的执行者,一个是事务的协调者,实际上整个分布式事务的运作都需要依靠协调者来维持: 在准备和提交阶段,会进行: 准备阶段: 一个分布式事务是由协调者来开启的,首先协调者会向所有的事务执行者发送事务内容,等待所有的事务执行者答复。 各个事务执行者开始执行事务操作,但是不进行提交,并将undo和redo信息记录到事务日志中。 如果事务执行者执行事务成功,那么就告诉协调者成功Yes,否则告诉协调者失败No,不能提交事务。 提交阶段: 当所有的执行者都反馈完成之后,进入第二阶段。 协调者会检查各个执行者的反馈内容,如果所有的执行者都返回成功,那么就告诉所有的执行者可以提交事务了,最后再释放锁资源。 如果有至少一个执行者返回失败或是超时,那么就让所有的执行者都回滚,分布式事务执行失败。 虽然这种方式看起来比较简单,但是存在以下几个问题: 事务协调者是非常核心的角色,一旦出现问题,将导致整个分布式事务不能正常运行。 如果提交阶段发生网络问题,导致某些事务执行者没有收到协调者发来的提交命令,将导致某些执行者提交某些执行者没提交,这样肯定是不行的。 XA分布式事务协议 - 3PC(三阶段提交实现) 三阶段提交是在二阶段提交基础上的改进版本,主要是加入了超时机制,同时在协调者和执行者中都引入了超时机制。 三个阶段分别进行: CanCommit阶段: 协调者向执行者发送CanCommit请求,询问是否可以执行事务提交操作,然后开始等待执行者的响应。 执行者接收到请求之后,正常情况下,如果其自身认为可以顺利执行事务,则返回Yes响应,并进入预备状态,否则返回No PreCommit阶段: 协调者根据执行者的反应情况来决定是否可以进入第二阶段事务的PreCommit操作。 如果所有的执行者都返回Yes,则协调者向所有执行者发送PreCommit请求,并进入Prepared阶段,执行者接收到请求后,会执行事务操作,并将undo和redo信息记录到事务日志中,如果成功执行,则返回成功响应。 如果所有的执行者至少有一个返回No,则协调者向所有执行者发送abort请求,所有的执行者在收到请求或是超过一段时间没有收到任何请求时,会直接中断事务。 DoCommit阶段: 该阶段进行真正的事务提交。 协调者接收到所有执行者发送的成功响应,那么他将从PreCommit状态进入到DoCommit状态,并向所有执行者发送doCommit请求,执行者接收到doCommit请求之后,开始执行事务提交,并在完成事务提交之后释放所有事务资源,并最后向协调者发送确认响应,协调者接收到所有执行者的确认响应之后,完成事务(如果因为网络问题导致执行者没有收到doCommit请求,执行者会在超时之后直接提交事务,虽然执行者只是猜测协调者返回的是doCommit请求,但是因为前面的两个流程都正常执行,所以能够在一定程度上认为本次事务是成功的,因此会直接提交) 协调者没有接收至少一个执行者发送的成功响应(也可能是响应超时),那么就会执行中断事务,协调者会向所有执行者发送abort请求,执行者接收到abort请求之后,利用其在PreCommit阶段记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源,执行者完成事务回滚之后,向协调者发送确认消息, 协调者接收到参与者反馈的确认消息之后,执行事务的中断。 相比两阶段提交,三阶段提交的优势是显而易见的,当然也有缺点: 3PC在2PC的第一阶段和第二阶段中插入一个准备阶段,保证了在最后提交阶段之前各参与节点的状态是一致的。 一旦参与者无法及时收到来自协调者的信息之后,会默认执行Commit,这样就不会因为协调者单方面的故障导致全局出现问题。 但是我们知道,实际上超时之后的Commit决策本质上就是一个赌注罢了,如果此时协调者发送的是abort请求但是超时未接收,那么就会直接导致数据一致性问题。 TCC(补偿事务) TCC是Try、Confirm、Cancel三个词语的缩写,TCC要求每个分支事务实现三个操作 :预处理Try、确认Confirm、撤销Cancel。Try操作做业务检查及资源预留,Confirm做业务确认操作,Cancel实现一个与Try相反的操作既回滚操作。TM首先发起所有的分支事务的try操作,任何一个分支事务的try操作执行失败,TM将会发起所有分支事务的Cancel操作,若try操作全部成功,TM将会发起所有分支事务的Confirm操作,其中Confirm/Cancel操作若执行失败,TM会进行重试。 分支事务失败的情况 : TCC分为三个阶段 :...

May 21, 2022 · 1 min · Rufus

消息队列是个啥

消息队列入门了解 之前看了许多博客,零零散散的,差不多了解了个大概。 (1 封私信) 消息队列(mq)是什么 - 知乎 (zhihu.com) Kafka简明教程 - 知乎 (zhihu.com) 消息队列本身是一个消息中间件,如同一个队列一样,生产者生产消息到消息队列里,然后消费者对队列中的消息进行消费。 它的作用主要有两点: 解耦消息的生产和消费。 缓冲。(流量高时削峰) 让消息被异步处理 消息队列造成的一些问题: 系统复杂性 本来蛮简单的一个系统,我代码随便写都没事,现在你凭空接入一个中间件在那,我是不是要考虑去维护他,而且使用的过程中是不是要考虑各种问题,比如消息重复消费、消息丢失、消息的顺序消费等等,反正用了之后就是贼烦。 数据一致性 这个其实是分布式服务本身就存在的一个问题,不仅仅是消息队列的问题,但是放在这里说是因为用了消息队列这个问题会暴露得比较严重一点。 你下单的服务自己保证自己的逻辑成功处理了,你成功发了消息,但是优惠券系统,积分系统等等这么多系统,他们成功还是失败你就不管了? 我说了保证自己的业务数据对的就好了,其实还是比较不负责任的一种说法,这样就像个渣男,没有格局,这样呀你的路会越走越窄的。 可用性 你搞个系统本身没啥问题,你现在突然接入一个中间件在那放着,万一挂了怎么办?我下个单MQ挂了,优惠券不扣了,积分不减了,这不是一个程序员能搞定的吧。 消息队列与消费者之间的投递方式 在 「消息队列由哪些角色组成?」 中,我们已经提到消息队列有 push 推送和 pull 拉取两种投递方式。 一种模型的某些场景下的优点,在另一些场景就可能是缺点。无论是 push 还是 pull ,都存在各种的利弊。 push 优点,就是及时性。 缺点,就是受限于消费者的消费能力,可能造成消息的堆积,Broker 会不断给消费者发送不能处理的消息。 pull 优点,就是主动权掌握在消费方,可以根据自己的消息速度进行消息拉取。 缺点,就是消费方不知道什么时候可以获取的最新的消息,会有消息延迟和忙等。 目前的消息队列,基于 push + pull 模式结合的方式,Broker 仅仅告诉 Consumer 有新的消息,具体的消息拉取,还是 Consumer 自己主动拉取。...

May 20, 2022 · 4 min · Rufus

SpringBean的加载机制

SpringBean的加载机制 (95条消息) 一文读懂 Spring Bean 的生命周期_老周聊架构的博客-CSDN博客_springbean的生命周期 之前用Bean直接无脑加注解,也没有特别关系bean创建前后,以及bean和spring容器间的一些关系,现在看面筋有问到这方面,速来恶补一番。 原先的一套说辞是:springioc容器先进行一波扫描,扫描bean的注解和xml配置,然后把扫描出来的bean封装成beandefinition这个数据结构,放到beandefinitionmap里面去。 但是,显然这不够详细因为还有很多细节没有讲到,比如实例化的时候前后的方法,属性赋值的时候Aware接口相关属性的赋值,还有初始化前后的方法,以及最后的销毁。 所以稍微详细一点的版本是:springioc容器先进行一波扫描,扫描bean的注解和xml配置,然后把扫描出来的bean封装成beandefinition这个数据结构, 然后对其进行实例化(前后会由InstantiationAwareBeanPostProcessor处理,执行一些操作),属性注入赋值(就是bean自带的一些成员变量进行赋值,如果实现了Aware接口,还得将相关信息通过重写的方法注入bean),初始化(自己配置的init-method方法),然后就放在在beandefinitionmap中,销毁(自己配置的destory方法)。 关于那个init-method和destorymethod,我的理解就是下面这样的。 TestBean.class @Slf4j public class TestBean { public void init() { log.info("初始化TestBean"); // DO STH. } public void destroy() { log.info("销毁TestBean"); // DO STH. } } CommonConfig.class @Slf4j @Configuration public class CommonConfig { @Bean(initMethod = "init", destroyMethod = "destroy") public TestBean testBean() { return new TestBean(); } }

May 10, 2022 · 1 min · Rufus

关于redis的锁几种机制

乐观锁操作 这里不考虑分布式的情况,用的是最简单的乐观锁。即在事务里,使用WATCH查看某个变量。 在事务提交时,如果WATCH的变量发生了改变,那么将取消本次事务。 显然,这是一种乐观锁的实现。 127.0.0.1:6379> multi 127.0.0.1:6379> watch ww 127.0.0.1:6379> set lock1 1 127.0.0.1:6379> exec 悲观锁操作 便是使用setnx指令,它的作用就是(set if not exist),用中文来说,就是设置一个键值对,如果它不存在,就设置成功,返回1,如果存在,则返回0。 127.0.0.1:6379> setnx lock_1 1 (integer) 1 127.0.0.1:6379> setnx lock_1 2 (integer) 0 127.0.0.1:6379> del lock_1 (integer) 1 通过这个指令,可以完成最基本的分布式锁操作,比如下图所示。 但是这种方式,仍然存在诸多问题。在这篇文章里紧接着讲了更多升级版本 (1 封私信) 怎样实现redis分布式锁? - 知乎 (zhihu.com) 如何解决操作资源时异常退出,不能释放锁? 给锁加一个过期时间,在redis里,就表现为设置锁的EXPIRE时间 127.0.0.1:6379> SETNX lock 1 // 加锁 (integer) 1 127.0.0.1:6379> EXPIRE lock 10 // 10s后自动过期 (integer) 1 127.0.0.1:6379> SET lock 1 EX 10 NX // 一条命令保证原子性执行 OK 如何确定过期时间? 举一个详细的场景来说明这个问题:会话A在操作共享资源时,由于锁到期了,就释放锁,然后另一个会话B来操作共享资源,发现没锁,于是加锁,这时,AB已经都在共享资源里了,这不合理。然后当A退出时,会释放锁,于是B的锁直接失效。...

May 8, 2022 · 1 min · Rufus