最近没事想自己写一套SSO的单点登录机制,于是再Sa-token上面学习了一下,Sa-token很优秀的实现了一套完整的单点登录机制,供用户进行使用。我选择其中的模式二,即客户端不同源,Redis同源的认证策略,进行了源码阅读和学习,这也是最常用的单点登录模型。

客户端不同源,认证中心Redis同源

首先讲一下,什么叫做同源和不同源,这个其实很容易理解,通俗来说就是是否在同一个域名下。
举个例子吧
客户端1:client1-sso.com
客户端2:client2-sso.com
认证中心:server-sso.com
我们知道客户端的是否登录这个机制,通常是通过cookie来完成的,现在如果client1跳转到认证中心登录,那么认证中心就会向client1中写入一个cookie,但是因为client1和client2不同源,这就带来了比较大的麻烦,cookie不共享啊!这咋办呢,sa-token是这样解决的。

  1. 用户访问客户端1,进入client1-sso.com,提示用户进行登录
  2. 用户点击登录,跳转到http://client1-sso.com/sso/login?back=http://client1-sso.com/,客户端对该路由进行检查,重定向到认证中心
  3. 用户进入认证中心http://server-sso.com/sso/auth?redirect=http://client1-sso.com/sso/login?back=http://client1-sso.com/,在这里就会有对应操作了,如果用户没有登录,那么认证中心应用程序的cookie里面必然就没有记录token字段,那么此时,就会跳转到认证中心登录界面
  4. 用户输入用户名和密码进行登录,登录成功后,就会往当前会话的认证中心中写入cookie。到这里为止,其实用户就已经完成了认证中心的单点登录了。
  5. 那么接下来,我们再次回到之前的client1,此时同样,我们还是要点击登录按钮,重复上述的操作。注意到第三步时,此时认证中心已经登录,就有了cookie,那么直接拿到了用户信息,同时认证中心生成一个ticket码,将这个ticket放到redis里面去。然后进行重定向,跳转到redirect记录的客户端登录地址http://client1-sso.com/sso/login?back=http://client1-sso.com/&ticket=xxxxxxxxx
  6. 客户端发现登录地址里面有ticket,就会立马连接到远程的redis上面,进行ticket对比,如果无误,就可以再进行检查拿到ticket里面的登录信息。客户端就会进行登录操作,将token写入客户端应用程序的cookie中。
  7. 自动登录完成后,cookie中也记录登录信息,用户返回到back记录的主页面。

那么到此为止,单点登录就已经完成了,从第5步到第7步,这些操作,实际上都是自动完成的。

再说一下,sa-token是如何实现注销的吧,其实明白了登录如何实现的,注销的原理就非常简单了。目的是客户端选择注销之后,用户需要认证中心重新登录。
1、用户在客户端点击注销,首先在客户端应用程序上删除token,这样就无法通过认证了
2、最关键的第二步,是要让认证中心的token也失效,sa-token中认证中心和客户端共用一个token存储库,实现的方式是将这个token从存储库中移除,就无法识别了,需要重新认证。

代码操作

讲了原理部分,那就看看sa-token是如何实现吧。看源码其实对于很多原理的理解会有很多帮助,实际上,通过这种图的形式来讲解原理是抽象的,当你阅读了源码之后,就会有很深刻的理解。更重要的地方在于,你可以按照别人的思路实现自己的一套SSO单点登录系统。

  • 客户端登录接口
    首先根据客户端登录接口,http://client1-sso.com/login,一般会有可能出现两个参数,一个是back,这个是必须要有的,相当于客户端登录成功后返回的主页url。另一个是ticket,这个可有可无。
    如果没有ticket,说明这个接口客户点击过来的,那么就需要重定向到认证中心去。
    如果有ticket就说明这个是认证中心登录成功后返回的,此时就可以拿着ticket去redis中拿用户信息loginId,然后直接用这个loginId进行登录,生成token,存到客户端的cookie中。
    在这里注意的是,ticket的校验机制,客户端应该与认证中心生成ticket的机制相对应。
 /*** SSO-Client端:登录地址 * @return 处理结果 */public static Object ssoLogin() {// 获取对象 SaRequest req = SaHolder.getRequest();SaResponse res = SaHolder.getResponse();SaSsoConfig cfg = SaSsoManager.getConfig();StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;// 获取参数 String back = req.getParam(ParamName.back, "/");String ticket = req.getParam(ParamName.ticket);// 如果当前Client端已经登录,则无需访问SSO认证中心,可以直接返回 if(stpLogic.isLogin()) {return res.redirect(back);}/** 此时有两种情况: * 情况1:ticket无值,说明此请求是Client端访问,需要重定向至SSO认证中心 * 情况2:ticket有值,说明此请求从SSO认证中心重定向而来,需要根据ticket进行登录 */if(ticket == null) {String serverAuthUrl = SaSsoUtil.buildServerAuthUrl(SaHolder.getRequest().getUrl(), back);return res.redirect(serverAuthUrl);} else {// ------- 1、校验ticket,获取 loginId Object loginId = checkTicket(ticket, Api.ssoLogin);// Be: 如果开发者自定义了处理逻辑 if(cfg.getTicketResultHandle() != null) {return cfg.getTicketResultHandle().apply(loginId, back);}// ------- 2、如果 loginId 无值,说明 ticket 无效if(SaFoxUtil.isEmpty(loginId)) {throw new SaSsoException("无效ticket:" + ticket).setCode(SaSsoExceptionCode.CODE_20004);} else {// 3、如果 loginId 有值,说明 ticket 有效,此时进行登录并重定向至back地址 stpLogic.login(loginId); return res.redirect(back);}}}
  • 认证中心授权地址
    接下来,我们看看认证中心的授权地址http://server-sso.com/sso/auth,通常会带着一个redirect参数,表示登录成功会跳转回的客户端地址,所谓授权地址,就是检查用户有没有登录的。认证中心会查找当前会话中有没有cookie,然后获取其中token信息,拿到对应的loginId。
    如果没有token,或者并没有获取到loginId,那么说明并没有登录,那么自然而然就会跳转到认证中心的登录地址进行登录。
    如果获取到了loginId,那就说明登录成功了,那么认证中心,就用这个loginId作为标志,生成一个ticket存到redis中。然后重定向到redirect参数中的客户端地址,并再带上一个参数ticket,这个ticket会在客户端用于去redis中获取loginId。
 /*** SSO-Server端:授权地址* @return 处理结果 */public static Object ssoAuth() {// 获取对象 SaRequest req = SaHolder.getRequest();SaResponse res = SaHolder.getResponse();SaSsoConfig cfg = SaSsoManager.getConfig();StpLogic stpLogic = SaSsoUtil.saSsoTemplate.stpLogic;// ---------- 此处有两种情况分开处理:// ---- 情况1:在SSO认证中心尚未登录,需要先去登录 if(stpLogic.isLogin() == false) {return cfg.getNotLoginView().get();}// ---- 情况2:在SSO认证中心已经登录,需要重定向回 Client 端,而这又分为两种方式:String mode = req.getParam(ParamName.mode, "");// 方式1:直接重定向回Client端 (mode=simple)if(mode.equals(SaSsoConsts.MODE_SIMPLE)) {String redirect = req.getParam(ParamName.redirect);SaSsoUtil.checkRedirectUrl(redirect);return res.redirect(redirect);} else {// 方式2:带着ticket参数重定向回Client端 (mode=ticket)  String redirectUrl = SaSsoUtil.buildRedirectUrl(stpLogic.getLoginId(), req.getParam(ParamName.redirect));return res.redirect(redirectUrl);}}
  • 认证中心登录地址
    这个接口http://server-sso.com/sso/doLogin相对于来说,就比较简单了。用户输入用户名和密码在认证中心进行登录,登录成功后,将token放到当前应用程序的cookie中就可以了。cookie中有了token信息,后面再跳转到认证中心授权地址的时候,就不用再重复登录。
 /*** SSO-Server端:RestAPI 登录接口 * @return 处理结果 */public static Object ssoDoLogin() {// 获取对象 SaRequest req = SaHolder.getRequest();SaSsoConfig cfg = SaSsoManager.getConfig();// 处理 return cfg.getDoLoginHandle().apply(req.getParam(ParamName.name), req.getParam(ParamName.pwd));}

文章的最后,真的很佩服有些大佬,Sa-token的作者真的很牛逼啊,这是一套非常完整的认证鉴权框架,实现的非常完美。不过使用上太过简单了,对于使用者而言,理解原理只能阅读源码了。

Sa-token SSO单点登录机制【源码】相关推荐

  1. [精华][推荐]CAS SSO实现单点登录实例源码

    1.因为是本地模拟sso环境,而sso的环境测试需要域名,所以需要虚拟几个域名出来,步骤如下: 2.进入目录C:\Windows\System32\drivers\etc 3.修改hosts文件 12 ...

  2. [精华][推荐]CAS SSO 实现单点登录实例源码

    1.修改server.xml文件,如下: 注意: 这里使用的是https的认证方式,需要将这个配置放开,并做如下修改: <Connector port="8443" prot ...

  3. Spring Security OAuth2.0 token生成与刷新机制源码阅读

    一.介绍 Spring Security Oauth2是目前市面上非常流行的实现了OAuth2.0协议的权限框架.本文会介绍其是如何获取token以及刷新token的. 二.AbstractEndPo ...

  4. Superset单点登录调整源码

    ///修改config.py from flask_appbuilder.security.manager import AUTH_REMOTE_USER AUTH_TYPE=AUTH_REMOTE_ ...

  5. CAS SSO 单点登录 【完整版】

    什么是单点登录?什么是SSO? SSO就是单点登录!!! SSO即Single Sign On. 可是为什么我们要单点登录呢?为什么不能把所有的系统做成一个war包里呢? 道理很简单啊,如果这个银行这 ...

  6. 通用权限管理系统组件 (GPM - General Permissions Manager) 中集成多系统的统一登录(数据库源码级)附源码...

    眼前有20万行以上的代码时很多人都会眼花缭乱,不知道从哪里开始下手了,甚至不会去研究几下就直接放弃了.其实大多时候没有想象的那么复杂,代码里一大部分都是有重复的,有本质上差别的部分还是很少的. 春节期 ...

  7. JAVA springboot ssm b2b2c多用户商城系统源码-SSO单点登录之OAuth2.0登录流程(2)

    上一篇是站在巨人的肩膀上去研究OAuth2.0,也是为了快速帮助大家认识OAuth2.0,闲话少说,我根据框架中OAuth2.0的使用总结,画了一个简单的流程图(根据用户名+密码实现OAuth2.0的 ...

  8. java ssm 多租户_(十一)java B2B2C 源码 多级分销springmvc mybatis多租户电子商城系统- SSO单点登录之OAuth2.0登录流程(2)...

    上一篇是站在巨人的肩膀上去研究OAuth2.0,也是为了快速帮助大家认识OAuth2.0,闲话少说,我根据框架中OAuth2.0的使用总结,画了一个简单的流程图(根据用户名+密码实现OAuth2.0的 ...

  9. Spring Cloud云架构 - SSO单点登录之OAuth2.0 根据token获取用户信息(4)

    上一篇我根据框架中OAuth2.0的使用总结,画了SSO单点登录之OAuth2.0 登出流程,今天我们看一下根据用户token获取yoghurt信息的流程: /** * 根据token获取用户信息 * ...

最新文章

  1. Win7 任务栏影藏、显示速度提升
  2. Python Tkinter小试
  3. 数据结构 二叉树
  4. dict()与{},list()与[]性能对比
  5. 基于Mac自带nginx、php,配置php服务器
  6. @SentinelResource注解实现热点限流
  7. 0918类对象重载,作业3
  8. Linux脏牛漏洞提权复现
  9. jsp框架html,GUI构建:[jsp风格的框架通常]对由模板生成的HTML代
  10. Jmeter高阶学习,运用NotePad++编写工程,随意复制多个工程到同一个工程
  11. 神经网络发展的五个阶段,神经网络发展历程
  12. HBase入门笔记(一)--Ubuntu无线网卡驱动配置
  13. c语言表达式判断语法错误题,C语言数据类型与表达式习题及答案.doc
  14. 古籍拆字 - 批量拆字成图 - js拆字 - js拆图 - js拆古籍 -导出svg矢量图
  15. 基于Spring Boot的讲师积分管理系统(毕业设计,毕设)
  16. c++ vector基本函数、排序、查找用法
  17. C--利用switch()浅浅做一个成绩等级划分小程序
  18. 第二十三章 天猫精灵控制ESP32(wifi+tcp+json)
  19. VScode远程调试remote development
  20. 开发实战分享|小程序扫码获取图书信息(内附详细教程)

热门文章

  1. jQuery DataTables的serverSide选项
  2. DP [Sdoi2010]地精部落
  3. 集成学习精讲02 - Bagging方法:多个基模型的聚合(SAP大神黄佳新作《零基础学机器学习》节选)
  4. nginx配置https登录,同时支持wss协议
  5. 量化选股——基于多因子模型的量化策略(第1部分—因子测算策略构建)
  6. centos使用yum安装提示:removing mirrorlist with no valid mirrors
  7. qt QTabWidget setTabsClosable
  8. python爬虫-爬取社区论坛房产信息-01
  9. Linux 开启22 端口
  10. 人工智能在教育领域的应用行业调研报告 - 市场现状分析与发展前景预测