本文介绍桌面和移动端的Native应用如何通过OAuth 2.0扮演登录用户访问阿里云API。

前提条件

Native应用扮演登录用户访问阿里云首先需要创建应用,为应用提供恰当的名称、OAuth范围、回调地址等关键信息。详情请参见创建应用。由于Native应用运行在非可信环境,无法有效保护应用密钥,因此Native应用不使用应用密钥。

说明 应用创建成功之后,可以在云账号内直接扮演用户。

基本流程

基本流程
  1. 用户通过浏览器登录Native应用。
  2. Native应用重定向到阿里云OAuth 2.0服务并将URL返回给浏览器。
    说明 如果用户还未登录,则会进一步重定向到阿里云登录服务。
  3. 用户通过浏览器登录阿里云OAuth 2.0服务并申请授权码。
  4. 阿里云OAuth 2.0服务重定向到Native应用并返回授权码。
  5. Native应用使用授权码向阿里云OAuth 2.0服务申请代表用户身份的令牌。
  6. 阿里云OAuth 2.0服务向Native应用返回令牌。
  7. Native应用通过获取的令牌向阿里云发起访问API的请求。
    说明 由于令牌可以代表用户身份,因此应用可以访问当前用户的资源。

Proof Key机制的原理

Native应用支持 Proof Key机制,用于每次获取授权码以及用授权码换取访问令牌。

说明 这一机制可以减轻针对授权码截获的攻击。
  1. Native应用生成:code_verifier,并保存好这个随机字符串。
    说明 code_verifier是一个高熵值的随机字符串,其取值为:[A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~",长度限制为:43~128个字符。
  2. 应用根据transform的方式选择生成code_challenge。应用在申请授权码的同时提交:code_challenge 以及生成code_challenge的方式。
    code_challenge = transform(code_verifier, [Plain|S256])
    方式 取值
    plain 如果 transform的方式选择为:plain,那么code_challengecode_verifier的值相同。
    S256 如果transform的方式选择为:S256,那么code_challenge等于code verifier的SHA256哈希值。
    code_challenge=BASE64URL-Encode(SHA256(ASCII(code_verifier)))
    说明 哈希算法的输入为:code_verifier 的ASCII编码串,哈希算法的输出字符串需要进行BASE64-URL编码。

    code_challenge选择方式计算示例:

    如果应用采用方式为S256,生成code_verifier的值为:dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk,那么code_challenge为:E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM

  3. 应用获取授权码后,在使用授权码换取访问令牌时,服务端通过计算判断是否颁发令牌。

    授权码需包括code_verifier,服务端按照应用选择的transform方式对code_verifier进行计算,将结果与code_challenge进行对比,如果一致则颁发访问令牌。

获取访问令牌

  1. Native应用通过浏览器将用户重定向到阿里云OAuth 2.0服务从而获取授权码。

    授权码的请求地址:https://signin.aliyun.com/oauth2/v1/auth

    表 1. 请求参数
    参数名称 是否必选 描述
    client_id 应用的身份ID。
    redirect_uri 创建应用的重定向URI之一。
    response_type 返回类型。根据OAuth 2.0协议,目前支持设置此参数的取值为:code
    scope 空格分隔的OAuth范围列表。如不指定此参数取值,则默认为应用的全部OAuth范围。
    state 应用通过state参数实现多种目的,例如:状态保持、作为nonce使用从而减少CSRF威胁等。state如果设置为任意字符串,阿里云OAuth 2.0服务会将请求中的state参数以及取值原样放到返回参数中以供后续使用。
    code_challenge_method 如果不指定此参数,则默认取值为:plain
    code_challenge 根据客户端指定的code_challenge_method,对随机生成的code_verifier进行转换和编码,转换的结果作为code_challenge参数的值在授权码请求中使用。
    说明 如果不指定此参数,则无法使用Proof Key机制,在使用授权码换取令牌时也不需要指定相应的code_verifier,若授权码被截获可以直接被用于换取访问令牌。

    请求示例

    https://signin.aliyun.com/oauth2/v1/authorize?
    client_id=98989****
    redirect_uri=meeting%3A%2F%2Fauthorize%2F
    &response_type=code
    &scope=openid%20%2Fworksuite%2Fuseraccess
    &state=123456****
    &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSst****
    &code_challenge_method=S256

    返回示例

    GET HTTP/1.1 302 Found
    Location: meeting://authorize/?code=ABAFDGDFXYZW888&state=123456****                     
  2. Native应用使用授权码向阿里云OAuth 2.0服务申请代表用户身份的令牌。

    换取访问令牌的请求地址:https://oauth.aliyun.com/v1/token

    表 2. 请求参数
    参数名称 是否必选 描述
    code 初始请求中获取的授权码。
    client_id 应用的身份ID。
    redirect_uri 初始请求中设置的参数。
    grant_type 根据OAuth 2.0协议, 取值为:authorization_code
    code_verifier 初始请求中生成的code verifier,对应于授权码请求中的code_challenge参数。

    请求示例

    POST /v1/token HTTP/1.1 
    Host: oauth.aliyun.com 
    Content-Type: application/x-www-form-urlencoded
    code=ABAFDGDFXYZW888&
    client_id=98989****
    redirect_uri=meeting://authorize/&
    grant_type=authorization_code&
    code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk                    
    表 3. 返回参数
    参数名称 描述
    access_token 访问令牌。访问令牌可以代表用户身份,应用使用此访问令牌来访问阿里云API。应用不需要理解访问令牌的含义,直接使用即可。
    expires_in 访问令牌的剩余有效时间,单位为秒。
    token_type 访问令牌的类型。取值为:Bearer
    id_token 身份令牌。id_token为OAuth签名的JWT(JSON Web Token)。如果初始请求的scope参数包含了openid,则返回身份令牌。
    refresh_token 刷新令牌。此参数可以直接使用,Native应用不需要指定访问令牌的值,可以直接获得刷新令牌。

    返回示例

    {
      "access_token": "eyJraWQiOiJrMTIzNCIsImVuYyI6****",
      "token_type": "Bearer",
      "expires_in": 3600,
      "refresh_token": "Ccx63VVeTn2dxV7ovXXfLtAqLLERA****",
      "id_token": "eyJhbGciOiJIUzI1****"
    }                      

获取新的访问令牌

换取访问令牌的请求地址:https://oauth.aliyun.com/v1/token

表 4. 请求参数
参数名称 是否必选 描述
refresh_token 用授权码换取访问令牌时获得的刷新令牌。
client_id 应用的身份ID。
grant_type 根据OAuth 2.0协议, 取值为:refresh_token

请求示例

POST /v1/token HTTP/1.1 
Host: oauth.aliyun.com 
Content-Type: application/x-www-form-urlencoded
refresh_token=Ccx63VVeTn2dxV7ovXXfLtAqLLERAH****
client_id=98989****
grant_type=refresh_token
表 5. 返回参数
参数名称 描述
access_token 新的访问令牌。应用使用新的访问令牌来访问阿里云API。
expires_in 访问令牌的剩余有效时间,单位为秒。
token_type 访问令牌的类型。取值为:Bearer

返回示例

{
  "access_token": "eyJraWQiOiJrMTIzNCIsImVuYyI6****",
  "token_type": "Bearer",
  "expires_in": 3600,
}                      
说明 本次请求的返回值与用授权码换取访问令牌的返回值一致,但不包含refresh_tokenid_token

撤销刷新令牌

Native应用获取了刷新令牌后,在用户退出登录应用时或用户将自己的账号从应用中移除时,必须撤销刷新令牌。

撤销刷新令牌的请求地址:https://oauth.aliyun.com/v1/revoke

表 6. 请求参数
参数名称 是否必选 描述
token 需要撤销的刷新令牌。
client_id 应用的身份ID。