请求访问令牌
您必须先在服务器侧执行以下操作,才能使用Amazon Device Messaging(ADM)将消息发送到应用实例:
- 获取并存储应用实例的注册ID;有关更多详细信息,请参阅集成您的应用。
- 交换用于获取当前访问令牌的OAuth客户端凭证。本文将介绍这一过程。
要发送消息以及了解有关ADM高层架构的信息,请参阅发送消息和ADM概述。
客户端凭证和访问令牌
要获取访问令牌,您的服务器需要向ADM服务器提供OAuth客户端凭证。您的客户端凭证将由亚马逊分配,它们是对应用唯一的两组数据: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.<十六进制客户端凭证>
|
client_secret
|
您的客户端凭证的“客户端密钥”部分。 |
client_secret=<YOUR_CLIENT_SECRET>
|
响应格式
在成功接收并解释您的POST请求消息之后,ADM会向您的服务器发送一条类似如下的HTTP响应消息:
X-Amzn-RequestId: <client ID>
Content-Type: application/json
{
"access_token":"Atc|<客户访问令牌>",
"expires_in":3600,
"scope":"messaging:push",
"token_type":"Bearer"
}
响应的标头包含以下字段:
标头 | 描述 | 示例 |
---|---|---|
X-Amzn-RequestId
|
由ADM创建的唯一标识请求的值。万一您在使用ADM时遇到问题,亚马逊可以使用此值来解决问题。 |
X-Amzn-RequestId: <十六进制请求ID>
|
Content-Type
|
资源的内容类型:application/json
|
Content-Type: application/json
|
当您的某一服务器成功请求访问令牌时,您将收到200状态代码响应,并且对该请求的响应的消息正文将包含访问令牌及其使用期限(以秒为单位)。
参数 | 描述 | 示例 |
---|---|---|
access_token
|
必须用于所有入队请求的访问令牌。 |
"access_token":"<十六进制客户访问令牌>"
|
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_id 、client_secret 、scope 、grant-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服务器的响应:
/**
* 要获取访问令牌,请向亚马逊发出HTTPS请求,
* 并提供client_id和client_secret值。
*/
public String getAuthToken(String clientId, String clientSecret) throws Exception
{
// 对包含clientID和clientSecret值的请求正文进行编码。
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");
// 利用访问令牌请求的基本URL来创建一个新的URL对象。
URL authUrl = new URL("https://api.amazon.com/auth/O2/token");
// 生成HTTPS连接。您无法通过HTTP建立连接。
HttpsURLConnection con = (HttpsURLConnection) authUrl.openConnection();
con.setDoOutput( true );
con.setRequestMethod( "POST" );
// 设置Content-Type标头。
con.setRequestProperty( "Content-Type" , "application/x-www-form-urlencoded" );
con.setRequestProperty( "Charset" , "UTF-8" );
// 通过连接发送编码的参数。
OutputStream os = con.getOutputStream();
os.write(body.getBytes( "UTF-8" ));
os.flush();
con.connect();
// 将响应转换为String对象。
String responseContent = parseResponse(con.getInputStream());
// 创建一个新的JSONObject来保存访问令牌并
// 从响应中提取令牌。
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();
}
Last updated: 2022年9月21日