xxl-sso源码解读(基于Cookie)

xxl-sso源码解读


前言

登录一直是所有系统的必不可少的一部分,也是极其重要的一个功能。随着技术思想的演变,通过解读许雪里大神的xxl-sso来了解处理跨域系统登录问题的方式和思路会对自己有个比较大的提升。当然下面的分析都是靠个人理解,如果有不对的地方希望可以在评论区指正。下面图片中代码看不清的话,点击一下放大就可以了。

一、XXL-SSO是什么?

XXL-SSO 是一个分布式单点登录框架。只需要登录一次就可以访问所有相互信任的应用系统。拥有”轻量级、分布式、跨域、Cookie+Token均支持、Web+APP均支持”等特性。

二、搭建步骤

具体搭建步骤请查看xxl-sso官网

三、系统简述

  • xxl-sso-server:中央认证服务,支持集群
  • xxl-sso-core:Client端依赖
  • xxl-sso-samples:单点登陆Client端接入示例项目
    • xxl-sso-web-sample-springboot:基于Cookie接入方式,供用户浏览器访问,springboot版本
    • xxl-sso-token-sample-springboot:基于Token接入方式,常用于无法使用Cookie的场景使用,如APP、Cookie被禁用等,springboot版本

1、xxl-sso-server

这个项目是整个sso的认证中心,未登录状态下访问其他系统就会重定向到该系统的登录页面,并进行认证授权。
在这里插入图片描述
XxlSsoConfig:项目启动时读取配置文件中的redis地址和redis过期时间来初始化redis
用户权限拦截器是让开发者自由去根据具体业务进行用户权限拦截验证
其他的文件都是可以结合实际情况定制开发

2、xxl-sso-core

这个项目是sso的核心,实际使用中其他系统需要引入这个项目的maven依赖。


Conf:存储自定义的一些常量值,为了避免魔法值
过滤器和处理类是重点,之后的源码解读会重点讲解

3、 xxl-sso-web-sample-springboot和xxl-sso-token-sample-springboot

这两个项目是简单搭建的使用案例,分别的基于cookie和token的接入方式。
在这里插入图片描述

四、基于Cookie方式

1、项目运行

首先启动xxl-sso-server中央认证服务
在这里插入图片描述

xxl-sso-server项目启动后,在初始化Bean时,XxlSsoConfig配置类由于实现了InitializingBean接口,会执行afterPropertiesSet(),将配置文件中的redis地址传入redis工具类中并初始化;设置sso登录操作类redis信息过期时间。

然后启动xxl-sso-web-sample-springboot项目,项目启动时XxlSsoConfig从配置文件中读取配置参数初始化redis和XxlSsoWebFilter过滤器。
在这里插入图片描述

XxlSsoWebFilter初始化时会将中央认证服务(xxl-sso-server)地址,登出地址和不需要过滤的地址初始化,初始化完成后会打印在控制台。在每次符合拦截条件的地址便会被拦截器拦截执行doFilter(),因为过滤器是单例的,所以项目启动时加载初始化后,上述三个参数在方法中一直可以使用。

在这里插入图片描述

2、首次登录

首次登录原理时序图
在这里插入图片描述

项目都启动完后,在浏览器中输入http://xxlssoclient1.com:8081/xxl-sso-web-sample-springboot/,模拟首次访问客户端应用,
首先会被xxl-sso-core中的XxlSsoWebFilter给拦截执行doFilter()方法,如下图所示,首先会从request中拿到请求路径,然后判断是否在白名单路径中,如果在的话则不再执行下面的操作,直接放行。
在这里插入图片描述

再往下走,如下图所示,判断本次请求是否是登出,登出操作后面再讲。
在这里插入图片描述
继续往下走,如下图所示,执行XxlSsoUser xxlUser = SsoWebLoginHelper.loginCheck(req, res);,执行这个方法是去获取登录对象,结果为null,执行第二个红框的代码,由于本次是get请求,没有request请求头中没有content-type,所以isJson=false,继续执行第三个红框中的代码,很明显是拼接url(http://xxlssoserver.com:8080/xxl-sso-server/login?redirect_url=http://xxlssoclient1.com:8081/xxl-sso-web-sample-springboot/),该url由认证中心的地址?redirect_url=本次请求的地址,然后重定向到该地址
bb836ea24f1fd23.png)
最后浏览器页面就变成下图所示,跳转到了认证中心提供的统一的登录页面
在这里插入图片描述
在输入用户名和密码后,点击登录,由于认证中心xxl-sso-server也集成了xxl-sso-core,但是没有配置xxl-sso-core中的XxlSsoWebFilter拦截器,所以不会被拦截,所以post请求登录后,直接访问到了xxl-sso-server后台/doLogin方法,代码如下图,首先是判断是否记住密码,然后根据用户名密码校验用户信息是否正确(此处可以根据业务对接数据库进行信息校验),信息校验成功将用户信息赋予XxlSsoUser对象,然后执行makeSessionId()根据XxlSsoUser生成sessionId,makeSessionId方法中根据用户的id拼接version来组成sessionId(version可以自行定义生成规则,但是不能重复),然后进行用户信息存储,执行SsoWebLoginHelper.login(),在此方法中首先根据生成的sessionid拿到用户id作为key执行SsoLoginStore.put(storeKey, xxlUser)将用户信息存入redis中,并设置过期时间,随后执行CookieUtil.set(response, Conf.SSO_SESSIONID, sessionId, ifRemember),将sessionid存入cookie中,方法比较简单就不赘述了,值得注意的是,如果是记住密码的话,因为cookie没法设置永不过期,就把cookie过期时间设置为Integer.MAX_VALUE,一个32位二进制最大的数。登录完成后,便将要访问的路径拼接sessionid然后重定向,路径为http://xxlssoclient1.com:8081/xxl-sso-web-sample-springboot/?xxl_sso_sessionid=1000_ea9a88a094b04b989deab53fcfd8d3f0。
在这里插入图片描述
此时http://xxlssoclient1.com:8081/xxl-sso-web-sample-springboot/?xxl_sso_sessionid=1000_ea9a88a094b04b989deab53fcfd8d3f0该路径是访问的应用系统xxl-sso-web-sample-springboot,所以被拦截进行处理,每次都是先判断是否在白名单和是否是登出操作,这个上面说过了就不赘述了,再往下是执行SsoWebLoginHelper.loginCheck(req, res),可以看到是从cookie中取不到sessionid,就从请求URL中拿到了xxl_sso_sessionid(就是sessionId,只是名字不同),然后执行SsoTokenLoginHelper.loginCheck(cookieSessionId),在此方法中根据sessionid拿到userid,再根据userid当做key去redis中取XxlSsoUser,将sessionid中的version和XxlSsoUser的version进行对比,这个加入verison对比的过程是乐观锁的实现,对比没有问题后,判断登录的时间有没有超过设定过期时间的一半,超过一半的话就重新赋予一个新的时间,返回XxlSsoUser给SsoWebLoginHelper.loginCheck(req, res),继续往下执行,此时执行 request.setAttribute(Conf.SSO_USER, xxlUser),将用户信息放到request域中,过滤器通过。
在这里插入图片描述
过滤器通过后,便进入IndexController,跳转到index页面了,到这里单点登录的流程就完成了。
在这里插入图片描述

3、跨域系统首次登录

时序图
在这里插入图片描述
根据上面的登录原理我们知道了,一个网站登陆之后会在cookie中添加一个sessionId,下次再访问该网站时,会拿到这个sessionId,然后判断登录信息是否有效。那如果是跨域呢,我们知道跨域时cookie是不共享的,难道访问http://xxlssoclient1.com:8081/xxl-sso-web-sample-springboot/登录后,再访问跨域的类似的系统如http://xxlssoclient1.com:8082/xxl-sso-web-sample-springboot/还需要登陆吗?根据我们的经验和使用习惯,肯定是不需要再登录的,这也是跨域sso要解决的问题。
我们copy一份xxl-sso-web-sample-springboot代码,创建xxl-sso-web-sample-springboot-twox项目,
启动项目,这样我们就有两个客户端了

  • http://xxlssoclient1.com:8081/xxl-sso-web-sample-springboot/
  • http://xxlssoclient2.com:8082/xxl-sso-web-sample-springboot/
    首先访问http://xxlssoclient1.com:8081/xxl-sso-web-sample-springboot/,首次登录后,然后在浏览器新开一个标签页输入http://xxlssoclient2.com:8082/xxl-sso-web-sample-springboot/,回车访问

首先还是会被XxlSsoWebFilter拦截器拦截,进行白名单和登出判断,然后在SsoWebLoginHelper.loginCheck(req, res)方法里从cookie和url请求参数中都拿不到sessionId,所以XxlSsoUser为null,根据if判断重定向到http://xxlssoserver.com:8080/xxl-sso-server/login?redirect_url=http://xxlssoclient2.com:8082/xxl-sso-web-sample-springboot/,
在这里插入图片描述
请求在xxl-sso-server的login方法,如下图,又一次执行了SsoWebLoginHelper.loginCheck(request, response),注意这次是从xxl-sso-server中央认证中心的cookie域中拿的sessionId,由于第一次登陆时该cookie已经有了sessionId,所以可以取到sessionId,利用xxl-sso-server的cookie来十分巧妙的解决了所有跨域或者不跨域系统的登录所遇到的cookie共享问题。拿到XxlSsoUser对象后,重定向到http://xxlssoclient2.com:8082/xxl-sso-web-sample-springboot/?xxl_sso_sessionid=1000_6451438d7ee3483c8b345e6b9e02d8f0,接下来的操作和首次登陆中最后几步操作一样,就不再赘述了。
在这里插入图片描述

4、再次访问

当再次访问已经登录过的系统时,由于之前的登录已经在cookie中设置了sessionId,所以只需要从cookie中取sessionId然后验证即可,原理比较简单。

5、登出操作

时序图
在这里插入图片描述
客户端登出时,会被拦截器拦截,如下图所示,判断是登出请求,删除该系统cookie中的sessionId信息,然后跳转到http://xxlssoserver.com:8080/xxl-sso-server/logout,重定向到xxl-sso-server去注销。
在这里插入图片描述
在xxl-sso-server中的logout方法中,首先执行 SsoWebLoginHelper.logout(request, response),从xxl-sso-server的cookie中拿到sessionId,再根据sessionId拿到userid作为key去redis删除登录用户信息,然后从cookie中清除sessionId。最后重定向到登录页面。
在这里插入图片描述
其他已经登录的系统再请求操作时,由于redis中已经删除了登录用户信息,所以获取用户信息失败,然后重定向xxl-sso-server服务,获取xxl-sso-server域下cookie失败,从redis中查询用户信息失败,跳转登陆页。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
该项目是采用目前比较流行的SpringBoot/SpringCloud构建微服务电商项目,项目叫 《果然新鲜》,实现一套串联的微服务电商项目。完全符合一线城市微服务电商的需求,对学习微服务电商架构,有非常大的帮助,该项目涵盖从微服务电商需求讨论、数据库设计、技术选型、互联网安全架构、整合SpringCloud各自组件、分布式基础设施等实现一套完整的微服务解决方案。 项目使用分布式微服务框架,涉及后台管理员服务、地址服务、物流服务、广告服务、商品服务、商品类别服务、品牌服务、订单服务 、购物车服务、首页频道服务、公告服务、留言服务、搜索服务、会员服务等。  系统架构图   SpringBoot+SpringCloud+SSM构建微服务电商项目使用SpringCloud Eureka作为注册中心,实现服务治理使用Zuul网关框架管理服务请求入口使用Ribbon实现本地负载均衡器和Feign HTTP客户端调用工具使用Hystrix服务保护框架(服务降级、隔离、熔断、限流)使用消息总线Stream RabbitMQ和 Kafka微服务API接口安全控制和单点登录系统CAS+JWT+OAuth2.0分布式基础设施构建分布式任务调度平台XXL-JOB分布式日志采集系统ELK分布式事务解决方案LCN分布式锁解决方案Zookeeper、Redis分布式配置中心(携程Apollo)高并发分布式全局ID生成(雪花算法)分布式Session框架Spring-Session分布式服务追踪与调用链Zipkin项目运营与部署环境分布式设施环境,统一采用Docker安装使用jenkins+docker+k8s实现自动部署微服务API管理ApiSwagger使用GitLab代码管理(GitHub  GitEE)统一采用第三方云数据库使用七牛云服务器对静态资源实现加速 开发环境要求JDK统一要求:JDK1.8Maven统一管理依赖 统一采用Docker环境部署编码统一采用UTF-8开发工具IDEA 或者 Eclipse 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值