认证与授权

  • 认证(Authentication)即确认该用户的身份是他所声明的那个人
  • 授权(Authorization)即根据用户身份授予他访问特定资源的权限

也就是说,当用户登录应用系统时,系统需要先认证用户身份,然后依据用户身份再进行授权。认证与授权需要联合使用,才能让用户真正登入并使用应用系统。

单系统登录

相对于单点登录(SSO),单系统登录是指单个应用系统的登录/注销机制。

HTTP 无状态协议

web 应用一般采用 B/S 架构,使用 HTTP 作为通信协议。HTTP 是无状态协议,浏览器的每一次请求,服务器会独立处理,不与之前或之后的请求产生关联。但这也同时意味着,任何用户都能通过浏览器访问服务器资源,如果想保护服务器的某些资源,必须限制浏览器请求;要限制浏览器请求,必须鉴别浏览器请求,响应合法请求,忽略非法请求;要鉴别浏览器请求,必须清楚浏览器请求状态。既然 HTTP 协议无状态,就需要服务器和浏览器之间共同维护一个状态,这就是会话机制。

login_http_inner

会话机制

浏览器第一次请求服务器,服务器创建一个会话(session),并将会话的 id 作为响应的一部分发送给浏览器,浏览器存储会话 id ,并在后续第二次和第三次请求中带上会话 id,服务器取得请求中的会话 id 就知道是否是同一个用户。

login_session_inner

web 应用一般通过 cookie 来实现会话机制,在浏览器第一次访问服务器时生成带 sessionid(在 tomcat 服务器中默认是 JSESSIONID) 的 cookie,并随请求返回到浏览器端,之后,浏览器会在每次发送 http 请求时自动附带 cookie 信息。

login_session_cookie_inner

登录状态

有了会话机制,再加上认证机制,我们就可以识别出浏览器每次访问时的 登录状态。首先,我们要求浏览器第一次请求服务器需要输入 用户名密码 验证身份,然后服务器拿到用户名与密码去数据库进行比对,正确的话说明当前持有这个会话的用户是合法用户,应该将这个会话标记为 已登录 的状态,并保存到会话对象(通常在内存数据库中,例如 Redis )中,同时将会话 id 返回给浏览器。当下一次浏览器访问时会带上会话 id ,服务器就可以在会话对象中查看是否是 已登录 状态。

login_inner

Basic 认证

HTTP 提供了一个基础的用于权限控制和认证的通用框架,即 HTTP Basic 认证(HTTP Basic authentication)。RFC 7617 定义了 HTTP Basic 认证的框架规则。服务器可以用来针对客户端的请求发送质询信息(challenge),客户端则可以用来提供身份验证凭证。

HTTP Basic 认证 的工作流程如下:

  1. 客户端发起资源请求。
  2. 服务器端向客户端返回 401(Unauthorized,未被授权的)状态码,并在 WWW-Authenticate 首部提供如何进行验证的信息,其中至少包含有一种质询方式。
  3. 有意向证明自己身份的客户端可以在新的请求中添加 Authorization 首部字段进行验证,字段值为身份验证凭证信息。通常客户端会弹出一个密码框让用户填写,然后发送包含有恰当的 Authorization 首部的请求。客户端使用 utf-8 编码用户名和密码,并进行 base64 编码返回给服务器端。
  4. 当服务器端收到一个合法认证信息时,若该认证不能获取请求资源的权限,服务器端会返回 403(Forbidden,拒绝访问)状态码,说明用户权限不够。

basic_inner

在上图所示的基本身份验证过程中,信息交换须通过 HTTPS(TLS) 连接来保证安全。

WWW-Authenticate 首部的格式如下:
WWW-Authenticate: <type> realm=<realm>

Authorization 首部的格式如下:
Authorization: <type> <credentials>

  • type 代表了认证的方式,对于 Basic 认证,typeBasic
  • realm 用来描述进行保护的区域,或者指代保护的范围。它可以是类似于 “访问xxx平台” 的消息,这样用户就可以知道他们正在试图访问哪一空间。
  • credentials 代表了用户凭证,对于 Baisc 认证,用冒号将用户名和密码进行拼接(如:username:password),然后用 base64 方式编码。

Basic 认证足够简单,但是有许多的问题:

  1. 由于用户名与密码是是以明文的形式在网络中进行传输的(尽管采用了 base64 编码,但是 base64 算法是可逆的),所以 Basic 认证方案并不安全。Basic 认证方案应与 HTTPS/TLS 协议搭配使用。
  2. 即使密码被强加密,第三方仍可通过加密后的用户名和密码进行重放攻击。
  3. 如果想再进行一次 BASIC 认证时,一般的浏览器却无法实现认证注销操作。
  4. 登录界面无法定制,依赖客户端实现,通常浏览器会弹出密码框让用户填写。
  5. 不支持双因子认证,容易被破解。
  6. 有些客户端支持避免弹出登录框,可以使用包含用户名和密码的经过编码的 URL(例如:https://username:password@www.example.com/),十分不安全。

单点登录

如今,web 应用早已从久远的单系统发展成为由多系统组成的应用群,面对如此众多的系统,用户难道要一个一个登录,然后一个一个注销吗?虽然单系统的登录解决方案很完美,但对于多系统应用群已经不再适用了,为什么呢?单系统登录解决方案的核心是 cookie,cookie 携带会话 id 在浏览器与服务器之间维护会话状态。但 cookie 是有限制的,这个限制就是 cookie 的作用域(通常对应网站的域名,参见 Cookie-作用域 ),浏览器发送 http 请求时会自动携带与该域匹配的 cookie ,而不是所有 cookie 。

login_domain_inner

既然这样,为什么不将 web 应用群中所有子系统的域名统一在一个顶级域名下?例如 “*.baidu.com” ,可以将它们的 cookie 域设置为 “baidu.com” 。

这种做法理论上是可以的,甚至早期很多多系统登录就采用这种同域名共享 cookie 的方式。然而,可行并不代表好,共享 cookie 的方式存在众多局限。首先,应用群域名得统一;其次,应用群各系统使用的技术(至少是 web 服务器)要相同,不然 cookie 的 key 值(在 tomcat 服务器中为 JSESSIONID )不同,无法维持会话,共享 cookie 的方式是无法实现跨语言技术平台登录的,比如 Java、PHP、.NET 系统之间;第三,cookie 共享要求顶级域名和子域名之间互相信任,在现实 web 系统设计中中有诸多限制,并不是十分安全。

因此,我们需要一种全新的登录方式来实现多系统应用群的登录,这就是单点登录。

单点登录( Single Sign On,简称 SSO )是指通过一次认证鉴权可以登录多个系统的一种认证授权方式。

登录

相比于单系统登录,SSO 需要一个独立的认证中心,只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。间接授权通过令牌实现,SSO 认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。这个过程,也就是单点登录的原理,用下图说明:

sso_inner

下面对上图简要描述:

  • 用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
  • sso认证中心发现用户未登录,将用户引导至登录页面
  • 用户输入用户名密码提交登录申请
  • sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌
  • sso认证中心带着令牌跳转会最初的请求地址(系统1)
  • 系统1拿到令牌,去sso认证中心校验令牌是否有效
  • sso认证中心校验令牌,返回有效,注册系统1
  • 系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源
  • 用户访问系统2的受保护资源
  • 系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
  • sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌
  • 系统2拿到令牌,去sso认证中心校验令牌是否有效
  • sso认证中心校验令牌,返回有效,注册系统2
  • 系统2使用该令牌创建与用户的局部会话,返回受保护资源

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

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

注销

单点登录自然也要单点注销,在一个子系统中注销,所有子系统的会话都将被销毁,用下面的图来说明:

sso_logout_inner

sso认证中心一直监听全局会话的状态,一旦全局会话销毁,监听器将通知所有注册系统执行注销操作

下面对上图简要说明:

  • 用户向系统1发起注销请求
  • 系统1根据用户与系统1建立的会话id拿到令牌,向sso认证中心发起注销请求
  • sso认证中心校验令牌有效,销毁全局会话,同时取出所有用此令牌注册的系统地址
  • sso认证中心向所有注册系统发起注销请求
  • 各注册系统接收sso认证中心的注销请求,销毁局部会话
  • sso认证中心引导用户至登录页面

部署

单点登录涉及sso认证中心与众子系统,子系统与sso认证中心需要通信以交换令牌、校验令牌及发起注销请求,因而子系统必须集成sso的客户端,sso认证中心则是sso服务端,整个单点登录过程实质是sso客户端与服务端通信的过程,用下图描述

sso_server_inner

sso认证中心与sso客户端通信方式有多种,这里以简单好用的 httpClient 为例,实际上 web service、rpc、restful api 都可以

实现

sso采用 C/S 架构,我们先看 sso-client 与 sso-server 要实现的功能(以下 sso-server 即指sso认证中心)

 sso-client

  • 拦截子系统未登录用户请求,跳转至sso认证中心
  • 接收并存储sso认证中心发送的令牌
  • 与sso-server通信,校验令牌的有效性
  • 建立局部会话
  • 拦截用户注销请求,向sso认证中心发送注销请求
  • 接收sso认证中心发出的注销请求,销毁局部会话

 sso-server

  • 验证用户的登录信息
  • 创建全局会话
  • 创建授权令牌
  • 与sso-client通信发送令牌
  • 校验sso-client令牌有效性
  • 系统注册
  • 接收sso-client注销请求,注销所有会话
  1. sso-client拦截未登录请求

    java 拦截请求的方式有 servlet、filter、listener 三种方式,我们采用 filter 。在sso-client中新建 LoginFilter.java 类并实现 Filter 接口,在 doFilter() 方法中加入对未登录用户的拦截

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    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拦截未登录请求

    拦截从sso-client跳转至sso认证中心的未登录请求,跳转至登录页面,这个过程与sso-client完全一样

  3. sso-server验证用户登录信息

    用户在登录页面输入用户名密码,请求登录,sso认证中心校验用户信息,校验成功,将会话状态标记为“已登录”

    1
    2
    3
    4
    5
    6
    @RequestMapping("/login")
    public String login(String username, String password, HttpServletRequest req) {
    this.checkLoginInfo(username, password);
    req.getSession().setAttribute("isLogin", true);
    return "success";
    }
  4. sso-server创建授权令牌

    授权令牌是一串随机字符,以什么样的方式生成都没有关系,只要不重复、不易伪造即可,下面是一个例子:

    1
    String token = UUID.randomUUID().toString();
  5. sso-client取得令牌并校验

    sso认证中心登录后,跳转回子系统并附上令牌,子系统(sso-client)取得令牌,然后去sso认证中心校验,在 LoginFilter.javadoFilter() 中添加几行

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    // 请求附带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);
    }

    verify() 方法使用 httpClient 实现,这里仅简略介绍, httpClient 详细使用方法请参考官方文档

    1
    2
    HttpPost httpPost = new HttpPost("sso-server-verify-url-with-token");
    HttpResponse httpResponse = httpClient.execute(httpPost);
  6. sso-server接收并处理校验令牌请求

    用户在sso认证中心登录成功后,sso-server创建授权令牌并存储该令牌,所以,sso-server对令牌的校验就是去查找这个令牌是否存在以及是否过期,令牌校验成功后sso-server将发送校验请求的系统注册到sso认证中心。

    令牌与注册系统地址通常存储在key-value数据库(如 redis )中,redis 可以为 key 设置有效时间也就是令牌的有效期。redis 运行在内存中,速度非常快,正好 sso-server 不需要持久化任何数据。

    令牌与注册系统地址可以用下图描述的结构存储在redis中,可能你会问,为什么要存储这些系统的地址?如果不存储,注销的时候就麻烦了,用户向sso认证中心提交注销请求,sso认证中心注销全局会话,但不知道哪些系统用此全局会话建立了自己的局部会话,也不知道要向哪些子系统发送注销请求注销局部会话。

    sso_redis_inner

  7. sso-client校验令牌成功创建局部会话

    令牌校验成功后,sso-client将当前局部会话标记为“已登录”,修改 LoginFilter.java,添加几行

    1
    2
    3
    if (verifyResult) {
    session.setAttribute("isLogin", true);
    }

    sso-client还需将当前会话 id 与令牌绑定,表示这个会话的登录状态与令牌相关,此关系可以用 java 的 hashmap 保存,保存的数据用来处理sso认证中心发来的注销请求

  8. 注销过程

    用户向子系统发送带有“logout”参数的请求(注销请求),sso-client拦截器拦截该请求,向sso认证中心发起注销请求

    1
    2
    3
    4
    String logout = req.getParameter("logout");
    if (logout != null) {
    this.ssoServer.logout(token);
    }

    sso认证中心也用同样的方式识别出sso-client的请求是注销请求(带有“logout”参数),sso认证中心注销全局会话

    1
    2
    3
    4
    5
    6
    7
    8
    @RequestMapping("/logout")
    public String logout(HttpServletRequest req) {
    HttpSession session = req.getSession();
    if (session != null) {
    session.invalidate(); //触发LogoutListener
    }
    return "redirect:/";
    }

    sso认证中心有一个全局会话的监听器,一旦全局会话注销,将通知所有注册系统注销

    1
    2
    3
    4
    5
    6
    7
    8
    public class LogoutListener implements HttpSessionListener {
    @Override
    public void sessionCreated(HttpSessionEvent event) {}
    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
    //通过httpClient向所有注册系统发送注销请求
    }
    }

常见单点登录协议

单点登录实现中,sso-client 与 sso-server 系统之间的协议对接是非常重要的一环,一般涉及的标准协议类型有 CAS、OAuth、OIDC、SAML 与 Kerberos。

CAS

Central Authentication Service 简称 CAS ,是一种常见的 B/S 架构的 SSO 协议。和其他任何 SSO 协议一样,用户仅需登录一次,访问其他应用则无需再次登录。

CAS 认证流程包括三部分的参与者:

  • Client: 通常为使用浏览器的用户
  • CAS Client: 实现CAS协议的web应用
  • CAS Server: 作为统一认证的CAS服务器

认证流程为:

cas_inner

  1. Client (终端用户)在浏览器里请求访问 Web 应用 example ;
  2. 浏览器发起一个 GET 请求访问 example 应用的主页 https://www.example.com;
  3. 应用 example 发现当前用户处于未登录状态,重定向( Redirect )用户至 CAS 服务器进行认证;
  4. 用户请求 CAS 服务器;
  5. CAS 发现当前用户在 CAS 服务器中处于未登录状态, 要求用户必须得先登录;
  6. CAS 服务器返回登录页面至浏览器;
  7. 用户在登录界面中输入用户名和密码(或者其他认证方式);
  8. 用户把用户名和密码通过 POST 请求提交至 CAS 服务器;
  9. CAS 对用户身份进行认证,若用户名和密码正确,则生成 SSO 会话, 且把会话 ID 通过 Cookie 的方式返回至用户的浏览器端(此时,用户在 CAS 服务端处于登录状态);
  10. CAS 服务器同时也会把用户重定向至 CAS Client , 且同时发送一个 Service Ticket ;
  11. CAS Client 收到这个 Service Ticket 以后,请求 CAS Server 对该 ticket 进行校验;
  12. CAS Server 把校验结果返回给 CAS Client , 校验结果包括该 ticket 是否合法,以及该 ticket 中包含对用户信息;
  13. 至此,CAS Client 根据 Service Ticket 得知当前登录用户的身份,CAS Client 处于登录态。

经过上述流程以后,CAS Server 和 CAS Client 都处于登录态,当用户如果访问另外一个 CAS Client 2 的时候,用户不需要再次认证,即会跳过5、6、7、8、9这几步,从而达到 SSO 的效果。

OAuth

Open Authorization,简称 OAuth ,一般指的是 OAuth2 协议。

OAuth2 解决的主要场景是: 第三方应用如何被授权访问资源服务器。整个流程参与者包括几个组成部分:

  • Resource Owner: 资源拥有者,通常为终端用户
  • Resource Server: 资源提供者
  • Authorization Server: 授权服务器
  • Client: 请求访问服务器的应用

抽象的授权流程大致为:

oauth2_inner

假定一个在线音乐服务,用户 zhangsan 想通过某音视频播放软件来播放在线音乐, 但是在播放音乐之前,该音视频软件必须得通过 OAuth server 认证授权,得到 zhangsan 的同意之后才能访问在线音乐。

在这个场景中,zhangsan 为 Resource Owner, 在线音乐服务为 Resource Server , 某音视频播放软件为 Client,OAuth server 作为 Authorization Server。

授权流程如下:

  1. 音视频软件向 zhangsan 发起授权请求,请求 zhangsan 同意访问在线音乐服务;
  2. 根据不同的授权模式, zhangsan 同意该授权,且返回一个”授权”给音视频服务;
  3. 音视频服务携带 zhangsan 的授权,请求 OAuth Server 颁发一个 Access Token, 用于访问在线音乐;
  4. OAuth Server 校验音视频服务自身的合法性之后,颁发 Access Token;
  5. 音视频服务携带 Access Token, 代表 zhangsan 请求访问在线音乐;
  6. 在线音乐服务校验完 Access Token 以后,提供音乐服务. 播放器开始播放音乐。

上述是一个抽象的授权流程,而在具体实现中,在前三步中会有几个变种,即不同的授权模式,常见的授权模式包括:

  • Authorization Code Grant: 认证码授权,最为常用,相对更安全
    oauth_acg_inner
  • Implicit Grant: 隐式授权,适用于SPA应用,不推荐,被PKCE模式所替代
    oauth_ig_inner
  • Resource Owner Password Credentials Grant: 资源拥有者密码授权,需要把用户的用户名和密码暴露给Client,只有在 Authorization Server 完全信任 Client 时才能采用,不推荐
    oauth_ropcg_inner
  • Client Credential Grant:客户端认证授权,没有用户概念,适用于服务端与服务端的调用
    oauth_ccg_inner

OIDC

OpenID Connect 简称 OIDC,是基于 OAuth2 扩展出来的一个协议。OAuth2 只定义了授权(Authorization)场景,OIDC 额外定义了认证(Authentication)的场景。

相比 OAuth2,OIDC 引入了 ID Token 等和 UserInfo 相关的概念:

  • OAuth2 协议,只是定义了 Access Token/Refresh Token,但这两个 token 是指为了保护 Resource Server,并没有 Resource Owner 的身份信息;
  • OIDC 引入了 ID Token 的概念,用这个 token 来表示这是 Resource Owner 的身份信息:
    • 标准化 ID Token 的格式,即 JWT
    • 标准化 ID Token 的内容,即 Standard Claims
  • OIDC 引入了关于如何获取详细的 UserInfo Endpoint ;
  • OIDC 定义了类似于 SAML Metadata 的 Discovery接口,俗称 Well-known 接,使客户端可以动态的获取 OIDC 服务相关的元数据描述信息

OIDC 协议的登录授权流程和 OAuth2 基本类似, 整个流程的参与者也类似,只不过换了个术语:

  • OpenID Provider:简称 OP,负责认证和授权
  • Relying Party:简称 RP,类似 OAuth2 中的 Client
  • End User: 终端用户

oidc_inner

认证与授权流程如下:

  1. RP 发送一个认证请求给 OP;
  2. OP 对 EU 进行身份认证,然后提供授权;
  3. OP 把 ID Token 和 Access Token (需要的话)返回给 RP;
  4. RP 使用 Access Token 发送一个请求 UserInfo EndPoint;
  5. UserInfo EndPoint 返回 EU 的 Claims。

OIDC 的授权模式有以下三种:

  1. Authorization Code Flow:使用 OAuth2 的授权码来换取 Id Token 和 Access Token 。
  2. Implicit Flow:使用 OAuth2 的 Implicit 流程获取 Id Token 和 Access Token 。
  3. Hybrid Flow:混合 Authorization Code Flow + Implici Flow 。

OIDC 并不包含 OAuth2 中的 Resource Owner Password Credentials Grant 模式 和 Client Credential Grant 模式,主要是因为 Resource Owner Password Credentials Grant 模式中,用户名和密码完全提供给了 Client(Relying Party) 不需要 ID Token 进行认证,而 Client Credential Grant 模式中没有 User 的角色,所以不需要认证。

SAML

Security Assertion Markup Language,简称 SAML,是一个基于 XML 的、用于实现不同业务实体(即系统或服务)之间,交换安全信息(例如认证信息、授权信息、主体属性信息等)的标准协议。SAML 标准定义了身份提供者(Identity Provider)和服务提供者(Service Provider)之间,如何通过 SAML 规范,采用加密和签名的方式来建立互信,从而交换用户身份信息。SAML 协议于2002年由 OASIS (结构化信息标准促进组织,Organization for the Advancement of Structured Information Standards) 组织提出,已经经历了 1.0,1.1,2.0 三个版本,在早期 B/S 架构的企业级应用中非常流行。

SAML 流程的参与者包括:

  • Asserting Party,即断言签发方,是签发断言的业务系统
  • Relying Party,即断言依赖方,是消费断言的业务系统
  • User,即用户,一般通过 Web 浏览器与两个业务系统进行交互

SAML 协议可以应用于多种不同的业务场景,在一些业务场景中,SAML 会定义不同的角色,各个业务系统在不同的场景中可以扮演不同的角色。以 Web 单点登录场景为例,在该场景下,SAML 协议中定义了 IdP(Identity Provider)和 SP(Service Provider)两种角色。

下面是大致的认证流程(SP Initiated):

saml_inner

  1. End User 从浏览器中请求访问某 SP:https://www.example.com
  2. https://www.example.com 发现用户未登录,则发起 SAML 的 AuthNRequest 请求至 IdP, 用户浏览器跳转至 IdP 页面;
  3. IdP 发现用户处于未登录状态,重定向用户至 IdP 的登录界面,请求用户进行身份验证
  4. 用户在登录页面中进行身份认证, 通常情况下需要校验用户名和密码;
  5. IdP 校验用户身份,若成功,则把包含着用户身份信息的校验结果,以 SAML Response 的形式,签名/加密发送给 SP;
  6. SP 拿到用户身份信息以后,进行签名验证/解密,拿到明文的用户身份信息,此时 SP 处于登录状态,可以对用户提供服务。

可以看到,在整个流程中,IdP 是负责颁发用户身份,SP 负责信任 IdP 颁发的用户身份, SP 和 IdP 之间的信任关系是需要提前建立的,即 SP 和 IdP 需要提前把双方的信息预先配置到对方,通过证书信任的方式来建立互信。

Kerberos

Kerberos 身份验证协议起源于麻省理工学院,是由“Athena”项目的工程师开发的。第一个公开发行的版本是于1980年末发布的 Kerberos 版本4。在被广泛的使用后,协议的开发者于1993年发布了 Kerberos 第五版本。Kerberos V5 现在成为 IETF 的标准,Windows Server 2003 中 Kerberos V5 的实现严格的遵循了RFC 1510定义的标准,另外,Kerberos 消息中的安全令牌(security tokens)的格式和机制遵循 RFC 1964 定义的标准。Kerberos 仅包含认证部分,不包括授权部分。

Kerberos 并不是一个 Web SSO 协议,它主要被应用于客户端与服务器认证。Windows2000 和后续的操作系统都默认 Kerberos 为其默认认证方法,苹果的 Mac OS X 也使用了 Kerberos 的客户和服务器版本,Red Hat Enterprise Linux4 和后续的操作系统使用了 Kerberos 的客户端和服务器版本。

Kerberos 认证流程的参与者主要包括:

  • AS(Authentication Server)= 认证服务器
  • KDC(Key Distribution Center)= 密钥分发中心
  • TGT(Ticket Granting Ticket)= 票据授权票据,票据的票据
  • TGS(Ticket Granting Server)= 票据授权服务器
  • SS(Service Server)= 特定服务提供端

其他协议

其他 SSO 相关协议还包括 OpenID、LID(Light-Weight Identity) 、Yadis、I-name、WS-Federation 等。

OpenID 最初是由大型社区 LiveJournal (建立于开源软件基础之上)的创办人 Brad Fitzpatrick 在2005年6月27日开发推出的一套身份识别系统,它采用分布式认证系统用于用户留言身份认证。

Light weight Identity (LID)或 Light Identity Management(LIdM)是一种用于在线数字身份的身份管理系统,部分由 NetMesh 开发。它于2005年初首次发布,是最初的基于 URL 的身份系统,随后被 OpenID 采用。LID 使用 URL 验证用户身份,并被几种开源协议采用,如 OpenID 、 Yadis 和 PGP/GPG 。

Yadis 是一种用于发现连接到 YadisID 的 OpenID 、 OAuth 和 XDI 等服务的通信协议。虽然 Yadis 旨在发现数字身份服务,但并不限于这些服务,可以很容易地包括其他服务。

I-name 是 XRI 的一种形式,XRI 是一种针对数字标识符的 OASIS 开放标准,旨在跨域和应用程序共享资源和数据。

WS-Federation,全称 Web Services Federation,简称 WS-Fed,属于 Web Services Security 框架的一部分,是由 OASIS 发布的标准协议,其主要贡献者是 Microsoft 和 IBM。WS-Fed 1.1 版本发布于2003年,最新的1.2版本标准发布于2009年。WS-Federation 标准基于 SOAP,定义了允许不同安全领域来协商 身份身份属性认证 信息的机制,主要应用在企业服务。

协议对比

上面简单介绍了主流的几种 SSO 协议,本质上它们大同小异,都是基于中心信任的机制,服务提供者和身份提供者之间通过互信来交换用户信息,只是每个协议信息交换的细节不同,或者概念上有些不同。

以下列举了常用 Web SSO 协议的比较:

功能 CAS OAuth OIDC SAML
支持认证(Authentication)
支持授权(Authorization)
协议最新版本 3.0 2.0 1.0 2.0
传输方式 HTTP HTTP HTTP HTTP
票据格式 Service ticket,Proxy ticket
没有标准格式
Access Token,Refresh Token
没有标准格式
Access Token,Refresh Token,ID Token
Access Token,Refresh Token 没有标准格式,ID Token采用 JWT 格式
Assertion,AuthNRequest,基于XML协议
主要应用场景 B/S架构,浏览器单点登录 B/S架构,浏览器单点登录,PKCE模式可用来实现移动端单点登录 B/S架构,浏览器单点登录 B/S架构,浏览器单点登录
优势 协议简单 1.协议简单,解决场景较多
2.成熟度高,社区支持广泛
基于 OAuth2,完全兼容 OAuth2 协议功能强大,涵盖场景多
劣势 场景单一 1.各厂商实现细节有差异
2.只定义了授权,未定义认证
1.协议过于庞大,可选实现过多
2.基于XML的签名&加密,技术复杂度更高
实践 玉符IDaaS 微信、企业微信、钉钉、QQ、玉符IDaaS 腾讯云IDaaS、玉符IDaaS 阿里云IDaaS、腾讯云IDaaS、玉符IDaaS

其他与认证授权相关的概念与术语

简称 全称 含义
AAA Authentication, Authorization & Accounting AAA是认证(Authentication)、授权(Authorization)和账号(Accounting)的简称,是网络安全中进行访问控制的一种安全管理机制,提供认证、授权和账号管理三种安全服务
4A Authentication, Authorization, Account & Audit 认证、授权、账号与审计
IAM Identity and Access Management 身份识别与访问管理
KMS Key Management Service 密钥管理服务
IdP Identity Provider 身份提供商,是一种存储和管理用户数字身份的服务
DaaS Directory as a Service 目录即服务
IDaaS Identity as a Service 身份即服务
PAM Pluggable Authentication Modules 可插拔认证模块,是由 Sun 公司提出的一种认证机制,通过提供一些动态链接库和一套统一的API,将系统提供的服务和该服务的认证方式分开,使得系统管理员可以灵活地根据需要给不同的服务配置不同的认证方式而无需更改服务程序,同时也便于向系统中添加新的认证手段
SASL Simple Authentication and Security Layer 简单验证和安全层
GSS-API The Generic Security Services Application Program Interface 通用安全服务应用程序接口
LDAP Lightweight Directory Access Protocol 轻型目录访问协议
openLDAP openLDAP 一个开源的LDAP服务器实现
AD Active Directory Microsoft 公司提供的LDAP实现
RADIUS Remote Authentication Dial In User Service 远程用户拨号认证系统,是应用最广泛的AAA协议,由RFC2865RFC2866定义