OAuth认证流程、Access Token 以及 Refresh Token简介

By SeaMount, Words: 2333

很多的网站、APP 都弱化了甚至没有搭建属于自己的账号体系,而是使用其它社会化的第三方登陆的方式,比如在登陆某个网站的时候选择通过 github 或者微信、微博等方式登陆,这样不仅免去了用户注册账号的麻烦,还可以获取用户的好友关系来增强自身的社交功能。

例如要通过 github 这样的第三方网站去登陆某个没有自己账号体系的平台,最传统的方式是直接在该平台的登陆页面输入 github 的账号密码,该平台通过用户的账号和密码去 github 上面获取用户的数据,但是这样做有很多缺陷:

  • 该平台需要明文保存用户的 github 账号和密码,不安全;
  • 该平台拥有获取用户在 github 的所有权限;
  • 用户只有修改密码,才能收回赋予该平台的权限,会导致其它获得用户授权的第三方应用全部失效;
  • 只要有一个第三方应用程序被破解,就会导致用户密码泄露,以及所有使用 github 登陆过的网站的数据泄漏;

为了解决以上问题,就有了 OAuth。

原理

OAuth在“客户端”和“服务端”之间设置了一个授权层(authorization layer)。“客户端”不能直接登陆“服务端”,只能登陆授权层,以此将用户与客户端区分开来。“客户端”登陆授权层所用的token与用户的密码不同,用户可以在登陆的时候,指定授权层 token 的权限范围和有效期。 “客户端”登陆授权层之后,“服务端”根据 token 的权限范围和有效期,向“客户端”开放用户存储的资料。

例如现在有一个平台为平台 A,平台 A 的登陆方式只有通过谷歌账号第三方登录机制登录:

Google 第三方认证流程

  1. 用户点击 Sign in with Google 跳转到授权页面,授权页面的 URL 中主要包含的参数有:
    • client_id: 在 Google 中申请应用 ID;
    • redirect_uri: 授权成功之后要跳转到的地址;
  2. 页面自动跳转到初始参数中 redirect_uri 定义的 URL,并自动在URL末尾添加一个 code 参数
  3. 平台 A 通过上一步获取的 code 参数换取 Token,平台 A 使用 POST https://oauth2.googleapis.com/token 获取 Token,需要包含以下参数:
    • client_id: 在 Google 申请的应用 ID;
    • client_secret: 在 Google 申请时提供的 APP Secret;
    • grant_type: 需要填写 authorization_code
    • code: 上一步获得的 code
    • redirect_uri: 回调地址,需要与注册应用里的回调地址以及第一步的 redirect_uri 参数
  4. 通过第三步的请求,接口返回Token和相关数据
     {
         "access_token": "ACCESS_TOKEN", // Token的值
         "expires_in": 1000, // 过期时间
         "uid": "1234567", // 当前授权用户的UID
     }
    
  5. 使用在第四步中获取到的access_token,就可以去获取用户的资源了
  6. Google返回用户信息,平台A进行处理,整个流程结束

通过以上方式,在平台A和Google之间建立了一个独立的权限层,这个权限由用户赋予,可以被用户随时取消,不同于第三方应用之间的相互独立,互不干扰,这样就解决了明文存放账号密码的问题。

Access Token

Access Token 是用于访问被保护的资源的一种凭据,它是一个不透明的字符串。一般 Access Token 的有效时间都比较短,如果想要用户不用频繁登录平台 A,就需要用到 Refresh Token。至于为什么需要用到 Refresh Token 而不是再次去获得 Access Token,主要是因为获取 Access Token 时需要使用到一个 code,而生成这个 code 需要用户再次进行操作,而有了 Refresh Token,用户就可以不用再次进行操作。

Refresh Token

在 OAuth 机制中,Refresh Token 并不是必须设置的,但是不设置 Refresh Token,则会增加用户登录的次数。Refresh token 的作用是刷新 Access token。为 Refresh Token 是保存在客户端的服务器上的,当前的 Access Token 失效或者过期时,Refresh Token 就会去获取一个新的 Token,Refresh Token 也是一个对客户端不透明的字符串。

一个比较有效的token返回结果如下:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
    "access_token": "MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
    "token_type": "bearer",
    "expires_in": 3600,
    "refresh_token": "IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
    "scope": "create"
}

大致流程如下:

Refresh Token 认证流程

  1. 客户端通过认证服务器请求认证;
  2. 认证服务器检验客户端认证是否有效,如果有效,返回一个 Access Token 和一个 Refresh Token;
  3. 客户端通过 Access Token 去请求服务器的资源;
  4. 如果 Access Token 有效,服务器返回给客户端资源,如果 Access Token 失效,服务器返回给客户端 Token 失效的信息,然后客户端会通过 Refresh Token 再次请求获取新的 Access Token;

Refresh Token 本身也是有过期时间的,一般会比 Access Token的过期时间长很多,如果想要将 Refresh Token 设置为永久有效,则可以通过配置参数实现。

参考连接

  1. An online reader for IETF RFCs
  2. access token response
Tags: OAuth