请求访问令牌


请求访问令牌

在可以使用 Amazon Device Messaging (ADM) 将消息发送到应用实例之前,在服务器端您必须事先执行以下操作:

  • 获取并存储应用实例的注册 ID;有关更多详细信息,请参阅集成您的应用

  • 交换当前访问令牌的 OAuth 客户端凭证。本文将介绍这一过程。

要发送消息以及了解有关 ADM 高级架构的信息,请参阅发送消息概览

客户端凭证和访问令牌

要获取访问令牌,您的服务器需要向 ADM 服务器提供您的 OAuth 客户端凭证。您的客户端凭证将由 Amazon 分配给您,它们是对应用唯一的两个数据片段:client_id 和 client_secret 值。您的服务器在其请求中使用您客户端凭证的这两个片段来获取 ADM 访问令牌。有关如何获取客户端凭证的信息,请参阅获取凭证

访问令牌是一种短​期元数据,它向 ADM 验证您服务器的身份,以便您可以发送消息。当您使用 ADM 发送一条消息时,该消息请求必须包含一个访问令牌。尽管服务器在任何给定时间只使用单个访问令牌,但您必须在旧访问令牌到期时获取一个新的。此外,尽管可以在多个服务器之间共享访问令牌,但是通常情况下,对于每个服务器来说,获取它们自己的访问令牌并独立地执行请求、跟踪以及使用它来发送消息更为方便。

请求格式

您的服务器通过在对 ADM 服务器的请求调用中提供您的客户端凭证,获取其访问令牌。您可以使用这一相同的请求获取初始访问令牌,也可以在先前的访问令牌到期时获取一个新的。

要获取访问令牌,您的服务器需要在 HTTPS 连接上发出一个 POST 请求。该请求与以下内容类似:

POST /auth/O2/token HTTP/1.1
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8

grant_type=client_credentials&scope=messaging:push&client_id=(YOUR_CLIENT_ID)&client_secret=(YOUR_CLIENT_SECRET)

该请求本身由两部分组成:标头和消息正文。标头必须包含以下字段:

字段 描述 示例
Content-Type 资源的内容类型。必须为:application/x-www-form-urlencoded Content-Type: application/x-www-form-urlencoded

对于消息正文的内容,您必须提供 URL 编码字符串,其中包含以下参数:

参数 描述 示例
grant_type 值必须为 client_credentials grant_type=client_credentials
scope 值必须为 messaging:push scope=messaging:push
client_id 您的客户端凭证的“客户端标识符”部分。 client_id=amzn1.iba-client.b2b360f8a77d457981625636121d6edf
client_secret 您的客户端凭证的“客户端密钥”部分。 client_secret=c559965801308f2bb79ca787 b1dfc8deece8a2fd7d7618946cec1635d26dcbfb

响应格式

在成功接收并解释您的 POST 请求消息之后,ADM 会向您的服务器发送一条类似如下的 HTTP 响应消息:

X-Amzn-RequestId: d917ceac-2245-11e2-a270-0bc161cb589d
Content-Type: application/json

{
  "access_token":"Atc|MQEWYJxEnP3I1ND03ZzbY_NxQkA7Kn7Aioev_OfMRcyVQ4NxGzJMEaKJ8f0lSOiV-yW270o6fnkI",
  "expires_in":3600,
  "scope":"messaging:push",
  "token_type":"Bearer"
}

响应的标头包含以下字段:

标头 描述 示例
X-Amzn-RequestId 由 ADM 创建的唯一标识请求的一个值。一旦您在使用 ADM 时遇到问题,亚马逊可以使用此值来解决问题。 X-Amzn-RequestId: d917ceac-2245-11e2-a270-0bc161cb589d
Content-Type 资源的内容类型:application/json Content-Type: application/json

当您的某一服务器成功请求访问令牌时,您将收到 200 状态代码响应,并且对该请求的响应的消息正文将包含访问令牌及其使用期限(以秒为单位)。

参数 描述 示例
access_token ​必须用于所有入队请求的一个访问令牌。 "access_token":"Atc|MQEWYJxEnP3I1ND03Zz..." (为了易于阅读缩短了示例)
expires_in 访问令牌使用期限的持续时间(以秒为单位)。例如,值“3600”表示访问令牌在从生成响应时算起的一个小时后到期。 "expires_in":3600
token_type ​所颁发的令牌的类型。支持的令牌类型之一。目前仅支持“持有者”令牌。 "token_type":"Bearer"
scope 访问令牌请求中指定的范围。值将为 messaging:push​。 "scope":"messaging:push"

ADM 对未成功的请求返回非 200 错误状态代码。对于非 200 代码,响应消息可能在 JSONObject 的正文中包含以下参数:

  • reason: ​不接受请求的原因。

下表列出了访问令牌请求可能的错误状态代码。

代码 描述 示例
400 此响应的原因包括:* 授权服务器不支持该内容类型。换而言之,它不是 application/x-www-form-urlencoded。* 请求缺少必需的参数:client_idclient_secretscopegrant-type。* 请求存在其他方面的格式错误。* 尚未对安全配置文件启用 ADM。请参阅​获取凭证​。 INVALID_REQUEST
400 客户端无权执行请求的操作。 UNAUTHORIZED_CLIENT
400 ​授权服务器不支持授予类型。换而言之,它不是 client_credentials UNSUPPORTED_GRANT_TYPE
400 所请求的范围无效。换而言之,它不是 messaging:push INVALID_SCOPE
401 客户端身份验证失败。 INVALID_CLIENT
500 出现内部服务器错误。请求者可以重试请求。 SERVER_ERROR
503 服务器暂时不可用。请求者必须按照响应中包含的 Retry-After 标头稍后重试。请参阅 HTTP/1.1 规范第 14.37 节以了解 Retry-After 值可能的格式。 SERVICE_UNAVAILABLE

发出令牌请求并处理响应

以下代码示例列举了您的服务器软件如何发送访问令牌请求并处理 ADM 服务器的响应:

/**
  * To obtain an access token, make an HTTPS request to Amazon
  * and include your client_id and client_secret values.
  */
public String getAuthToken(String clientId, String clientSecret) throws Exception
{
     // Encode the body of your request, including your clientID and clientSecret values.
     String body = "grant_type="    + URLEncoder.encode("client_credentials", "UTF-8") + "&" +
                   "scope="         + URLEncoder.encode("messaging:push", "UTF-8")     + "&" +
                   "client_id="     + URLEncoder.encode(clientId, "UTF-8")             + "&" +
                   "client_secret=" + URLEncoder.encode(clientSecret, "UTF-8");

     // Create a new URL object with the base URL for the access token request.
     URL authUrl = new URL("https://api.amazon.com/auth/O2/token");

     // Generate the HTTPS connection.You cannot make a connection over HTTP.
     HttpsURLConnection con = (HttpsURLConnection) authUrl.openConnection();
     con.setDoOutput( true );
     con.setRequestMethod( "POST" );

     // Set the Content-Type header.
     con.setRequestProperty( "Content-Type" , "application/x-www-form-urlencoded" );
     con.setRequestProperty( "Charset" , "UTF-8" );
     // Send the encoded parameters on the connection.
     OutputStream os = con.getOutputStream();
     os.write(body.getBytes( "UTF-8" ));
     os.flush();
     con.connect();

     // Convert the response into a String object.
     String responseContent = parseResponse(con.getInputStream());

     // Create a new JSONObject to hold the access token and extract
     // the token from the response.
     org.json. JSONObject parsedObject = new org.json.JSONObject(responseContent);
     String accessToken = parsedObject.getString("access_token");
     return accessToken;
}

private String parseResponse(InputStream in) throws Exception
{
     InputStreamReader inputStream = new InputStreamReader(in, "UTF-8" );
     BufferedReader buff = new BufferedReader(inputStream);

     StringBuilder sb = new StringBuilder();
     String line = buff.readLine();
     while (line != null )
     {
       sb.append(line);
       line = buff.readLine();
     }

     return sb.toString();
}