一、什么是单点登录?

单点登录的英文名叫做:Single Sign On(简称SSO)。

初学/以前的时候,一般我们就单系统,所有的功能都在同一个系统上。

所有的功能都在同一个系统上

后来,我们为了合理利用资源和降低耦合性,于是把单系统拆分成多个子系统。

  • 回顾:分布式基础知识

拆分成多个子系统

比如阿里系的淘宝和天猫,很明显地我们可以知道这是两个系统,但是你在使用的时候,登录了天猫,淘宝也会自动登录。

登录了天猫,淘宝也登录了

简单来说,单点登录就是在多个系统中,用户只需一次登录,各个系统即可感知该用户已经登录。

二、回顾单系统登录

在我初学JavaWeb的时候,登录和注册是我做得最多的一个功能了(初学Servlet的时候做过、学SpringMVC的时候做过、跟着做项目的时候做过…),反正我也数不清我做了多少次登录和注册的功能了…这里简单讲述一下我们初学时是怎么做登录功能的。

HTTP是无状态的协议

众所周知,HTTP是无状态的协议,这意味着服务器无法确认用户的信息。于是乎,W3C就提出了:给每一个用户都发一个通行证,无论谁访问的时候都需要携带通行证,这样服务器就可以从通行证上确认用户的信息。通行证就是Cookie

如果说Cookie是检查用户身上的”通行证“来确认用户的身份,那么Session就是通过检查服务器上的”客户明细表“来确认用户的身份的。Session相当于在服务器中建立了一份“客户明细表”

HTTP协议是无状态的,Session不能依据HTTP连接来判断是否为同一个用户。于是乎:服务器向用户浏览器发送了一个名为JESSIONID的Cookie,它的值是Session的id值。其实Session是依据Cookie来识别是否是同一个用户

所以,一般我们单系统实现登录会这样做:

  • 登录:将用户信息保存在Session对象中
  • - 如果在Session对象中能查到,说明已经登录
  • 如果在Session对象中查不到,说明没登录(或者已经退出了登录)
  • 注销(退出登录):从Session中删除用户的信息
  • 记住我(关闭掉浏览器后,重新打开浏览器还能保持登录状态):配合Cookie来用

我之前Demo的代码,可以参考一下:

 /*** 用户登陆*/
@PostMapping(value = "/user/session", produces = {"application/json;charset=UTF-8"})
public Result login(String mobileNo, String password, String inputCaptcha, HttpSession session, HttpServletResponse response) {//判断验证码是否正确if (WebUtils.validateCaptcha(inputCaptcha, "captcha", session)) {//判断有没有该用户User user = userService.userLogin(mobileNo, password);if (user != null) {/*设置自动登陆,一个星期. 将token保存在数据库中*/String loginToken = WebUtils.md5(new Date().toString() + session.getId());user.setLoginToken(loginToken);User user1 = userService.userUpload(user);session.setAttribute("user", user1);CookieUtil.addCookie(response, "loginToken", loginToken, 604800);return ResultUtil.success(user1);} else {return ResultUtil.error(ResultEnum.LOGIN_ERROR);}} else {return ResultUtil.error(ResultEnum.CAPTCHA_ERROR);}
}
/*** 用户退出*/
@DeleteMapping(value = "/session", produces = {"application/json;charset=UTF-8"})
public Result logout(HttpSession session, HttpServletRequest request, HttpServletResponse response) {//删除session和cookiesession.removeAttribute("user");CookieUtil.clearCookie(request, response, "loginToken");return ResultUtil.success();
}
/**
* @author ozc
* @version 1.0
* <p>
* 拦截器;实现自动登陆功能
*/
public class UserInterceptor implements HandlerInterceptor {@Autowiredprivate UserService userService;public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {User sessionUser = (User) request.getSession().getAttribute("user");// 已经登陆了,放行if (sessionUser != null) {return true;} else {//得到带过来cookie是否存在String loginToken = CookieUtil.findCookieByName(request, "loginToken");if (StringUtils.isNotBlank(loginToken)) {//到数据库查询有没有该CookieUser user = userService.findUserByLoginToken(loginToken);if (user != null) {request.getSession().setAttribute("user", user);return true;} else {//没有该Cookie与之对应的用户(Cookie不匹配)CookieUtil.clearCookie(request, response, "loginToken");return false;}} else {//没有cookie、也没有登陆。是index请求获取用户信息,可以放行if (request.getRequestURI().contains("session")) {return true;}//没有cookie凭证response.sendRedirect("/login.html");return false;}}}
}

总结一下上面代码的思路:

  • 用户登录时,验证用户的账户和密码
  • 生成一个Token保存在数据库中,将Token写到Cookie中
  • 将用户数据保存在Session中
  • 请求时都会带上Cookie,检查有没有登录,如果已经登录则放行

Cookie的作用是什么?和Session有什么区别?

Cookie 和 Session都是用来跟踪浏览器用户身份的会话方式,但是两者的应用场景不太一样。

Cookie 一般用来保存用户信息 比如①我们在 Cookie 中保存已经登录过的用户信息,下次访问网站的时候页面可以自动帮你登录的一些基本信息给填了;②一般的网站都会有保持登录也就是说下次你再访问网站的时候就不需要重新登录了,这是因为用户登录的时候我们可以存放了一个 Token 在 Cookie 中,下次登录的时候只需要根据 Token 值来查找用户即可(为了安全考虑,重新登录一般要将 Token 重写);③登录一次网站后访问网站其他页面不需要重新登录。

ession 的主要作用就是通过服务端记录用户的状态。典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了。

Cookie 数据保存在客户端(浏览器端),Session 数据保存在服务器端。

Cookie 存储在客户端中,而Session存储在服务器上,相对来说 Session 安全性更高。如果使用 Cookie 的一些敏感信息不要写入 Cookie 中,最好能将 Cookie 信息加密然后使用到的时候再去服务器端解密。

三、多系统登录的问题与解决

3.1 Session不共享问题

单系统登录功能主要是用Session保存用户信息来实现的,但我们清楚的是:多系统即可能有多个Tomcat,而Session是依赖当前系统的Tomcat,所以系统A的Session和系统B的Session是不共享的。

解决系统之间Session不共享问题有一下几种方案:

  • Tomcat集群Session全局复制(集群内每个tomcat的session完全同步)【会影响集群的性能呢,不建议】
  • 根据请求的IP进行Hash映射到对应的机器上(这就相当于请求的IP一直会访问同一个服务器)【如果服务器宕机了,会丢失了一大部分Session的数据,不建议】
  • 把Session数据放在Redis中(使用Redis模拟Session)【建议

我们可以将登录功能单独抽取出来,做成一个子系统。

抽取出来成为子系统

抽取出来成为子系统

SSO(登录系统)的逻辑如下:

// 登录功能(SSO单独的服务)
@Override
public TaotaoResult login(String username, String password) throws Exception {//根据用户名查询用户信息TbUserExample example = new TbUserExample();Criteria criteria = example.createCriteria();criteria.andUsernameEqualTo(username);List<TbUser> list = userMapper.selectByExample(example);if (null == list || list.isEmpty()) {return TaotaoResult.build(400, "用户不存在");}//核对密码TbUser user = list.get(0);if (!DigestUtils.md5DigestAsHex(password.getBytes()).equals(user.getPassword())) {return TaotaoResult.build(400, "密码错误");}//登录成功,把用户信息写入redis//生成一个用户tokenString token = UUID.randomUUID().toString();jedisCluster.set(USER_TOKEN_KEY + ":" + token, JsonUtils.objectToJson(user));//设置session过期时间jedisCluster.expire(USER_TOKEN_KEY + ":" + token, SESSION_EXPIRE_TIME);return TaotaoResult.ok(token);
}

其他子系统登录时,请求SSO(登录系统)进行登录,将返回的token写到Cookie中,下次访问时则把Cookie带上:

public TaotaoResult login(String username, String password, HttpServletRequest request, HttpServletResponse response) {//请求参数Map<String, String> param = new HashMap<>();param.put("username", username);param.put("password", password);//登录处理String stringResult = HttpClientUtil.doPost(REGISTER_USER_URL + USER_LOGIN_URL, param);TaotaoResult result = TaotaoResult.format(stringResult);//登录出错if (result.getStatus() != 200) {return result;}//登录成功后把取token信息,并写入cookieString token = (String) result.getData();//写入cookieCookieUtils.setCookie(request, response, "TT_TOKEN", token);//返回成功return result;
}

总结:

  • SSO系统生成一个token,并将用户信息存到Redis中,并设置过期时间
  • 其他系统请求SSO系统进行登录,得到SSO返回的token,写到Cookie中
  • 每次请求时,Cookie都会带上,拦截器得到token,判断是否已经登录

到这里,其实我们会发现其实就两个变化:

  • 将登陆功能抽取为一个系统(SSO),其他系统请求SSO进行登录
  • 本来将用户信息存到Session,现在将用户信息存到Redis

3.2 Cookie跨域的问题

上面我们解决了Session不能共享的问题,但其实还有另一个问题。Cookie是不能跨域的

比如说,我们请求<https://www.google.com/>时,浏览器会自动把google.com的Cookie带过去给google的服务器,而不会把<https://www.baidu.com/>的Cookie带过去给google的服务器。

这就意味着,由于域名不同,用户向系统A登录后,系统A返回给浏览器的Cookie,用户再请求系统B的时候不会将系统A的Cookie带过去。

针对Cookie存在跨域问题,有几种解决方案:

  1. 服务端将Cookie写到客户端后,客户端对Cookie进行解析,将Token解析出来,此后请求都把这个Token带上就行了
  2. 多个域名共享Cookie,在写到客户端的时候设置Cookie的domain。
  3. 将Token保存在SessionStroage中(不依赖Cookie就没有跨域的问题了)

到这里,我们已经可以实现单点登录了。

3.3 CAS原理

说到单点登录,就肯定会见到这个名词:CAS (Central Authentication Service),下面说说CAS是怎么搞的。

如果已经将登录单独抽取成系统出来,我们还能这样玩。现在我们有两个系统,分别是www.java3y.com和www.java4y.com,一个SSOwww.sso.com

现在我们有三个系统

首先,用户想要访问系统Awww.java3y.com受限的资源(比如说购物车功能,购物车功能需要登录后才能访问),系统Awww.java3y.com发现用户并没有登录,于是重定向到sso认证中心,并将自己的地址作为参数。请求的地址如下:

  • www.sso.com?service=www.java3y.com

sso认证中心发现用户未登录,将用户引导至登录页面,用户进行输入用户名和密码进行登录,用户与认证中心建立全局会话(生成一份Token,写到Cookie中,保存在浏览器上)

4步过程

随后,认证中心重定向回系统A,并把Token携带过去给系统A,重定向的地址如下:

  • www.java.com?token=xxxxxxx

接着,系统A去sso认证中心验证这个Token是否正确,如果正确,则系统A和用户建立局部会话(创建Session)。到此,系统A和用户已经是登录状态了。

第五步和第六步

此时,用户想要访问系统Bwww.java4y.com受限的资源(比如说订单功能,订单功能需要登录后才能访问),系统Bwww.java4y.com发现用户并没有登录,于是重定向到sso认证中心,并将自己的地址作为参数。请求的地址如下:

  • www.sso.com?service=www.java.com

注意,因为之前用户与认证中心www.sso.com已经建立了全局会话(当时已经把Cookie保存到浏览器上了),所以这次系统B重定向到认证中心www.sso.com是可以带上Cookie的。

认证中心根据带过来的Cookie发现已经与用户建立了全局会话了,认证中心重定向回系统B,并把Token携带过去给系统B,重定向的地址如下:

  • www.java.com?token=xxxxxxx

接着,系统B去sso认证中心验证这个Token是否正确,如果正确,则系统B和用户建立局部会话(创建Session)。到此,系统B和用户已经是登录状态了。

系统B的流程图

看到这里,其实SSO认证中心就类似一个中转站

end:如果你觉得本文对你有帮助的话,记得点赞转发,你的支持就是我更新动力。

啥是单点登陆?淘宝和天猫是如何实现同时登陆的?相关推荐

  1. JAVA模拟淘宝、天猫登录

    有时候需要对淘宝.天猫平台进行频繁操作,会触发平台风控,需要我们登陆之后才能进行操作,或者有些功能淘宝开放平台并没有提供api接口,只能通过人工登录进行操作,但是频繁的人工操作比较浪费时间.因此对于模 ...

  2. 为什么淘宝、天猫和旺信的 App 不整合成一个?

    首先,淘宝用户定位是低价,用户群买东西更偏向于低价,但是,这并不意味着低价用户从不买高价产品.就像很多人买衣服会在淘宝买,但是买电器却会在天猫商城买.用户的交叉性导致了在实际应用场景中不会单单只上淘宝 ...

  3. 提高 10 倍性能,揭秘淘宝、天猫背后的图片存储如何扛住双十一巨流?| 问底中国 IT 技术演进...

    2019天猫"双11",零点钟声刚过去1分36秒,成交额已突破100亿元人民币,最终成交额为2684亿,又一次刷新了世界记录. 对象存储OSS作为淘宝.天猫.支付宝等核心阿里App ...

  4. 实现从淘宝(天猫)定时抓取订单数据、打印电子面单并保存到ERP表中

    实现从淘宝(天猫)定时抓取订单数据.打印电子面单并保存到ERP表中 前言 实现思路 代码片段参考 前言 最近有厂商提出想把天猫店铺的数据拿到后台ERP管理系统中,并能实现线下打印电子面单功能.接手这个 ...

  5. 在iOS应用中跳转到淘宝或天猫客户端商品详情页

    最近做iOS项目的时候遇到一个需求,启动图片后是广告页,点击广告页,跳转到淘宝或天猫的商品详情页. 具体需要是这样: 1)安装了淘宝:跳转到淘宝详情页. 2)没装淘宝,装了天猫:跳转到天猫详情页 3) ...

  6. Android 使用 Scheme 启动淘宝,天猫等其他APP

    最近在开发一个购物的APP,在应用内直接跳转到淘宝,天猫,京东等其它购物APP,一番查找研究后找到了解决方法. 直接上结论代码(这也是很多人喜欢看的): //需要传入的 scheme 类型的商品地址 ...

  7. Android开源库V - Layout:淘宝、天猫都在用的UI框架,赶紧用起来吧!

    前言 V- Layout 是阿里出品的基础 UI 框架,用于快速实现页面的复杂布局,在手机天猫 Android版 内广泛使用 让人激动的是,在上个月V- Layout终于在Github上开源! Git ...

  8. Python自动登陆淘宝并爬取商品数据

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. 基本开发环境 Python 3.6 Pycharm import time from sel ...

  9. C++ 代码模拟登录淘宝、天猫、支付宝等电商网站的实现

    有关C++ 代码模拟登录淘宝.天猫.支付宝等电商网站的实现, 在群上有很多人问, 想来有许多人对此非常感兴趣, 其中的厉害关系在此不做深究, 这篇文章也仅仅提供一些基础的实现方法, 由于整个过程中基本 ...

最新文章

  1. vue cli根据不同的环境打包
  2. it行业php,什么是IT行业
  3. 利用ServletFileUpload组件上传文件
  4. C 中 main 函数的参数
  5. c语言入口及出口参数说明,麻烦帮忙指出一下这个函数的入口参数和出口参数呀!...
  6. 修完 1300 万行代码,我帮苹果省下 2 亿美元,但没拿到承诺的千万股票
  7. ECUG 早鸟票热卖中 | 大咖聚首 探索云计算下一个十年
  8. 使用生成器创建新的迭代模式
  9. 追新求快的时代,别让 Java Web 开发必备工具 Tomcat 变成“熟悉的陌生人”!
  10. 2022年自考专业考试(计算机应用)离散数学模拟冲刺题
  11. 重装Linux系统后的软件安装 及 常见操作_持续更新...
  12. 分类流控qdisc之htb
  13. perl中tr的用法
  14. git push 时出现错误error: failed to push some refs to ‘https://gitee.com/**.git‘
  15. 基于云虚拟机的代码覆盖率
  16. 计算机的桌面图标都可以重新命名对吗,windows上哪个图标不能重命名
  17. 关于嵌入式面试的一些题
  18. 消防应急疏散指示系统在居民住宅区的应用
  19. ORACLE给指定用户授权表的部分权限
  20. 内存按字节 (Byte)编址,地址从A0000H到DFFFFH,共有多少个字节呢?

热门文章

  1. python 等比例裁剪图片
  2. 里氏代换原则 (Liskov Substitution Principle, LSP)
  3. 从零开始的Linux 阿里云ECS服务器搭建、FileZilla和宝塔
  4. 刚刚,一页马克思手稿在阿里拍卖上拍到了290万
  5. 光伏项目电力监控系统的重要
  6. 如何建立一个网站?规划、设计、目的、原则、宣传(三)
  7. 【转】伽马校正(Gamma Correction)
  8. 计算机网络安全评估,计算机网络系统安全性分析及评估
  9. 动画项目中问题及解决方案(V客学院知识分享)
  10. UCenter 1.6 数据字典