SSO架构分析

SSO技术架构(Single Sign On)

1.SSO的背景

在多系统共存的环境下,用户在一处登录后,就可以不用在其他系统中重新登录,有了SSO技术,用户的使用成本更低、更加友好。

比如我们平时使用的淘宝、天猫、支护宝这三个应用,只需要登录其中一个应用,我们就可以直接访问这三个系统,而无需重新登录。

技术特点总结

一个账户,一次登录,即可访问多个系统

2.HTTP会话机制的简单介绍

2.1.http的无状态协议

http无状态协议

在http协议中,是属于无状态的,这就意味着任何用户都能够访问服务器资源!

但是对于有些系统而言,我们服务器端是需要区分出用户的,比如支付宝、淘宝等系统

2.2.http的会话(session)机制

既然http协议是无状态的,那么我们是否可以引入有状态协议呢?


http会话机制

那么会话协议怎么来实现呢?

  • cookie
  • 请求参数

2.2.多系统的复杂性

在前面的部分,我们介绍了关于单个系统,是如何实现会话机制的。那么多系统该如何处理呢?


多系统复杂性

web系统发展为多系统组成的应用群,但是这个复杂度应该由系统内部承担,而不是用户。如果每次访问一个新系统,都需要重新登录一次,对于用户体验而言,是难以接受的!

既然如此,我们是否能够实现在多系统间,登陆一次,即可所有系统都能够访问呢?


一次登录

在前面的部分,我们提到过,单系统的会话机制,可以使用请求参数cookie的技术来实现,但是在真实的环境中,基本不采用请求参数的方式,原因很简单,请求参数的方式安全性太差了,非常容易受到攻击。但是cookie是有限制的,cookie的域受限于相同的域名!比如下面的场景

用户访问(天猫)http://tmall.com/,(淘宝)http://taobao.com,(支付宝)https://www.alipay.com/三个域名时
三个域名的cookie是不能够跨域名携带传输的

也就是,如果使用常规的cookie技术,是无法解决多系统的会话机制的。
那么是否可以统一这些系统到一个顶级域名下面呢,比如:*.baidu.com?是的,该方案能够实现,但是存在一个比较大的缺点,那就是对域名有着非常严格的要求!

3.大杀器,SSO

相比较单系统登录,SSO架构需要一个单独的认证中心,用于处理用户的登录。其他的系统不提供登录入口,只需要接受认证中心的间接授权即可。

3.1.单点登录

SSO架构

用户登录成功之后,会与sso认证中心及各个子系统建立会话,用户与sso认证中心建立的会话称为全局会话,用户与各个子系统建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过sso认证中心。全局会话与局部会话存在的约束关系:

  • 局部会话存在,全局会话一定存在
  • 全局会话存在,局部会话不一定存在
  • 全局会话销毁,局部会话必须销毁

3.2.单点注销

在一个子系统中注销,那么其他子系统的会话都会被注销


单点注销

3.3.部署架构

部署架构

在这里面,很关键的一点就是区分:sso-client、sso-server

3.4.系统架构

系统架构

4.SSO的实现

sso-client的功能

  • 拦截系统的请求,如果未登录,直接跳转到sso-server登录界面
  • 接收并存储sso-server发送过来的令牌
  • 与sso-server保持通信,检验令牌的有效性
  • 建立局部会话
  • 拦截用户的注销请求,向sso-server发送注销请求
  • 接收sso-server发送的注销请求,摧毁局部会话

sso-server的功能

  • 提供登录界面
  • 认证用户的登录信息,创建授权令牌,发送令牌给sso-client
  • 创建全局会话
  • 检验sso-client发送过来的令牌有效性
  • 系统注册
  • 接收sso-client的注销请求,注销全局会话,通知sso-client注销局部会话

核心代码
1.sso-client拦截未登录请求

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    HttpSession session = req.getSession();

    if (session.getAttribute("isLogin")) {
        chain.doFilter(request, response);
        return;
    }
    //跳转至sso认证中心
    res.sendRedirect("sso-server-url-with-system-url");
}

2.sso-server创建令牌

String token = UUID.randomUUID().toString();

3.sso-client取得令牌并去sso-server校验令牌的有效性

// 请求附带token参数
String token = req.getParameter("token");
if (token != null) {
    // 去sso认证中心校验token
    boolean verifyResult = this.verify("sso-server-verify-url", token);
    if (!verifyResult) {
        res.sendRedirect("sso-server-url");
        return;
    }
    chain.doFilter(request, response);
}

参考附录

  • 架构设计 | 单点登录(SSO),从原理到实现
  • xxl sso
  • 漫谈单点登录
  • cookie,session,token

你可能感兴趣的:(SSO架构分析)