Native应用登录阿里云

本文介绍桌面和移动端的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_challengeE9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-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,若授权码被截获可以直接被用于换取访问令牌。

    prompt

    该参数用于指定服务器是否需要提示用户进行授权操作。

    如果指定,会强制要求用户进行授权,即使该阿里云账号已经做过授权,也需要重新授权。如果不指定,则只在该阿里云账号第一次使用该应用时要求授权。

    取值:admin_consent,表示服务端会在向客户端返回信息之前展示授权页面。

    请求示例

    https://signin.aliyun.com/oauth2/v1/auth?
    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。