1. 登录系统设计

  • 方式一:session 复制
  • 方式二:session 不复制 → 分布式 session(session 公用)
    • 问题:因为浏览器同源策略,有跨域访问的问题。导致浏览器从A系统获取的session,没法带到B系统(两者域名不同)
    • 解决:nginx 反向代理(解决浏览器cookie复制问题),或者用二级域名
    • 缺点:高并发情况下不适合
  • 方式三:无状态回话管理
    • 用户在某一个系统登录,返回 token
      • 首次登录,去数据库校验,成功后,下发签名

image.png

  1. - 签名需要服务端的秘钥进行加密,防止被伪造。校验的时候同样把头+体+盐进行hash
  2. - JwtUtil.java

2. 实现一个开放平台

2.1 如何实现一个开放平台呢?

一个完整的开放平台由 4 个体系组成,分别是:开放平台网关、授权中心、开发者中心、控制后台。
image.png
其中 开放平台是分成四个服务的。API 网关压力是最大的。

2.2 大体如何交互

image.png

3. 开放平台的权限安全的诉求

3.1 平台开发者权限验证

基于 APP KEY 与 secret 实现,需要达到以下三个目的:

  1. 防串改
  2. 防伪造
  3. 防重复使用签名

业务请求具体参数
image.png
签名规则:

  1. 已指定顺序拼接字符串 secret + method + param + token + timestamp + secret
  2. 使用 MD5 进行加密,再转化成大写

服务端验证流程:
image.png

3.2 用户权限验证

用户权限是指第三方系统是否具备某部分用户指定范围的授权。比如第三方系统访用户的订单信息。其主要两种交互模式如下

1. 自定授权模式

该模式下第三方应用必须是 WEB 系统,有自己的服务器。
比如:开一个网店,全平台(京东、天描、唯品会)→ 全网发布系统:(VWEB 应用-WEB 服务)

2. 手动授权模式

在自动授权模式下第三应系统必须是有自己的服务器,如果没有则自己的服务器就必须采用手动授权模式,该模式是指,在线下通过浏览器交互自动生成一个长效期 Token,并手动配置至第三方应用当中。

4. 如何基于 OAuth2.0 协议实现授权服务

4.1 认知 OAuth2.0

OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。OAuth2.0协议是OAuth协议的升级版,现在已经逐渐成为单点登录(SSO)和用户授权的标准。

例如:目前主流的互联网网站除了可以使用“用户名+密码”模式和“手机号+验证码”模式登录外,很多还提供了第三方账号登录,比如最常见的QQ登录、微博登录、百度账号登录、GitHub登录。而这些第三方登录方式就是采用了 OAuth2.0 协议实现。

为什么使用 OAuth2.0 ?
  1. 用户不再使用大量的账号
  2. 用于单点登录(所有需要登录的产品都请求同一个登录授权中心,进行统一登录授权处理)
  3. 用于分布式系统的权限控制
    • 因为基于OAuth2.0协议获得的令牌(Access Token)同时关联了接入的第三方应用、授权用户、权限范围等信息。因此,在第三方应用拿着Token请求资源的时候,资源服务应用就可以很容易根据其访问权限返回相应的数据。

在认证和授权的过程中涉及的各方包括:

  1. 服务提供方:开放平台内部-应用体系
  2. 用户:商城买家、和卖家
  3. 客户端,要访问服务提供方资源的第三方应用
  4. 资源服务器:开放平台==》网关
  5. 认证服务器:开放平台==》授权中心

在 OAuth2.0 当中支持的授权模式

  • 授权码模式(authorization code)
    • 功能最完整,流程最严密的模式
  • 简化模式((implicit))
    • 跳过了请求授权码(Authorization Code)的步骤,直接通过浏览器向授权服务端请求令牌(Access Token)。这种模式的特点是所有步骤都在浏览器中完成,Token对用户可见,且请求令牌的时候不需要传递client_secret进行客户端认证。
  • 密码模式(resource owner password credentials)
    • 用户向第三方客户端提供自己在授权服务端的用户名和密码,客户端通过用户提供的用户名和密码向授权服务端请求令牌(Access Token)
  • 客户端模式(client credentials)

4.2 授权码模式说明

授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与服务提供商“的认证服务器进行互动。

该模式在开放平台中的实现:
image.png
image.png

授权码模式(authorization code)授权的流程
  1. 通过 client_id 请求授权服务端,获取 **Authorization Code**
  2. 通过 Authorization Codeclient_idclient_secret 请求授权服务端,在验证完 Authorization Code 是否失效以及接入的客户端信息是否有效(通过传递的client_id 和 client_secret 信息和服务端已经保存的客户端信息进行匹配)之后,授权服务端生成 **Access Token****Refresh Token** 并返回给客户端。
  3. 客户端通过得到的 Access Token 求资源服务应用,获取需要的且在申请的 Access Token 权限范围内的资源信息。


对应的请求参数
第一步:获得 code**
image.png

第二步:通过 code 换取 token
image.png
示例:百度开放平台的返回
若参数无误,服务器将返回一段JSON文本,包含以下参数:

  • access_token:要获取的Access Token。
  • expires_in:Access Token的有效期,以秒为单位(30天的有效期)。
  • refresh_token:用于刷新Access Token 的 Refresh Token,所有应用都会返回该参数(10年的有效期)。
  • scope:Access Token最终的访问范围,即用户实际授予的权限列表(用户在授权页面时,有可能会取消掉某些请求的权限)。
  • session_key:基于http调用Open API时所需要的Session Key,其有效期与Access Token一致。
  • session_secret:基于http调用Open API时计算参数签名用的签名密钥。

    1. {
    2. "expires_in": 2592000,
    3. "refresh_token": "22.247946a05a327ia929b74354c3670cb2.315360000.1847863585.321432378-13484254",
    4. "access_token": "21.e2eb8577t4a68a32y23b61300eda8811.2592000.1536795385.321432378-13484254",
    5. "session_secret": "e8f9ee40de92862cc35c343n5da2fcfb",
    6. "session_key": "9mnRIQsyTR+0yfB3liSUjqGvk8F369TRfHJidz9iA0wDg\/KDBKZtGHACpXfULPjeX1YBWkKAtHSG\/OLXYKQHCuO4Zg2JiBwFtA==",
    7. "scope": "basic"
    8. }

    若请求错误,服务器将返回一段JSON文本,包含以下参数:

  • error:错误码,关于错误码的详细信息请参考百度OAuth2.0错误响应

  • error_description:错误描述信息,用来帮助理解和解决发生的错误。

项目实例:**在普通 JavaWeb 项目中实现百度 OAuth2.0 授权登录(包含具体项目代码)**

  • 本地代码:/Users/zhangchuanqiang/IdeaProjects-study/OAuth2.0Demo

4.3 简化模式说明

在自动授权模式下第三应系统必须是有自己的服务器,如果没有则自己的服务器就必须采用手动授权模式,该模式是指,在线下通过浏览器交互自动生成一个长效期 Token,并手动配置至第三方应用当中。

  1. 基于用户 KEY 与 secret 等参数引导弹开授权 WEB 页
  2. 用户输入用户和密码后返回授权确认页
  3. 用户确认后获得 Token
  4. 用户将 Token 保存至第三应用

原型图说明:
桌面应用登录采用第三方授权
image.pngimage.png
image.png

5. OAuth2.0 授权与单点登录(SSO)的区别

单点登录的英文名是 Single Sign On,因此一般简称为SSO。它的用途在于,不管多么复杂的应用群,只要在用户权限范围内,那么就可以做到,用户只需要登录一次就可以访问权限范围内的所有应用子系统。对于用户而言,访问多个应用子系统只需要登录一次,同样在需要注销的时候也只需要注销一次。

5.1 OAuth2.0 授权与单点登录的区别

根据 OAuth2.0 授权与单点登录的概念,我们可以得知二者至少存在以下几点区别:

  1. 从信任角度来看。OAuth2.0 授权服务端和第三方客户端不属于一个互相信任的应用群(通常都不是同一个公司提供的服务),第三方客户端的用户不属于 OAuth2.0 授权服务端的官方用户;而单点登录的服务端和接入的客户端都在一个互相信任的应用群(通常是同一个公司提供的服务),各个子系统的用户属于单点登录服务端的官方用户。
  2. 从资源角度来看。OAuth2.0 授权主要是让用户自行决定——“我”在OAuth2.0服务提供方的个人资源是否允许第三方应用访问;而单点登录的资源都在客户端这边,单点登录的服务端主要用于登录,以及管理用户在各个子系统的权限信息。
  3. 从流程角度来看。OAuth2.0 授权的时候,第三方客户端需要拿预先“商量”好的密码去获取Access Token;而单点登录则不需要。

5.2 单点登录服务端的设计

对于一个接入单点登录的子系统而言,进行单点登录需要以下两个步骤:

  1. client 请求单点登录服务端,获取 Access Token
  2. client 因为不能判断给它的 Access Token 是单点登录服务端返回还是用户伪造,所以需要再次请求单点登录服务端,校验 Access Token 是否有效,如果有效则返回用户基本信息以及相应的用户在 client 上所属的角色、权限等信息

因此,单点登录服务端的设计主要围绕这两个接口展开,其主要流程是这样的:
image.png

5.3 数据库表的设计

提示:我在下面只介绍一些表的主要字段,这个Demo中使用的完整的表结构可以参考:https://gitee.com/zifangsky/OAuth2.0Demo/blob/master/rbac_db.sql
(1)sso_client_details:
接入单点登录的子系统详情表。类似于百度的百度百科、百度知道、百度贴吧等应用子系统,每个想要接入单点登录的子系统都需要事先在服务端这里“备案”。一方面是为了防止用户在服务端登录成功生成的Access Token被重定向到非法网站,从而导致用户的Access Token被窃取;另一方面是记录接入的子系统的注销URL,便于开发单点注销功能。所以主要需要以下几个字段:

  • client_name:子系统的名称
  • redirect_url:获取Access Token成功后的回调URL
  • logout_url:用户在子系统的注销URL(用户登录状态可以分为:全局登录——在单点登录服务端的登录状态;局部登录——在子系统的登录状态,注销的时候需要同时注销用户在单点登录服务端和应用子系统的登录状态)


(2)sso_access_token:
单点登录的Access Token信息表。**这个表主要体现出哪个用户在哪个子系统登录,以及生成的令牌的结束日期是哪天。所以主要需要以下几个字段:

  • access_token:Access Token字段
  • user_id:表明是哪个用户登录
  • client_id:表明是在哪个子系统登录
  • expires_in:过期时间戳,表明这个Token在哪一天过期


(3)sso_refresh_token:
单点登录的Refresh Token信息表。**这个表主要用来记录Refresh Token,在设计表结构的时候需要关联它对应的sso_access_token表的记录。所以主要需要以下几个字段:

  • refresh_token:Refresh Token字段
  • token_id:它对应的sso_access_token表的记录
  • expires_in:过期时间戳

5.4 单点登录服务端主要接口代码实现

这个Demo的单点登录服务端的完整可用源码可以参考:https://gitee.com/zifangsky/OAuth2.0Demo/tree/master/ServerDemo