• 沒有找到結果。

使用AK(Access Key ID)、SK(Secret Access Key)对请求进行签名。

生成 AK、SK

如果已生成过AK/SK,则可跳过此步骤,找到原来已下载的AK/SK文件,文件名一般 为:credentials.csv。

如下图所示,文件包含了租户名(User Name),AK(Access Key Id),SK(Secret Access Key)。

4-3 credential.csv 文件内容

AK/SK生成步骤:

1. 注册并登录管理控制台。

2. 将鼠标移至用户名,在下拉列表中单击“我的凭证”。

3. 单击“访问密钥”。

4. 单击“新增访问密钥”,进入“新增访问密钥”页面。

5. 按照界面提示输入验证码或登录密码,单击“确定”,下载密钥,请妥善保管。

生成签名

生成签名的方式和APP认证相同,用AK代替APP认证中的AppKey,SK替换APP认证中 的AppSecret,即可完成签名和请求。您可使用Java、Go、Python、C#、

JavaScript、PHP、C++、C、Android进行签名和访问。

须知

客户端须注意本地时间与时钟服务器的同步,避免请求消息头X-Sdk-Date的值出现较 大误差。

API网关(即API管理)除了校验时间格式外,还会校验该时间值与网关收到请求的时 间差,如果时间差超过15分钟,API网关将拒绝请求。

5 创建用于前端自定义认证的函数

操作场景

自定义认证包括前端自定义认证与后端自定义认证,前端自定义认证指APIG利用校验 函数对收到的API请求进行安全认证,后端自定义认证指API后端服务利用校验函数,

对来自APIG转发的API请求进行安全认证。

如果您想要使用自己的认证系统对API的访问进行认证鉴权,您可以在API管理中创建 一个前端自定义认证来实现此功能。在使用前端自定义认证对前端请求进行认证鉴权 前,您需要先在FunctionGraph创建一个函数,通过函数定义您所需的认证信息。函数 创建完后,作为自定义认证的后端函数,对API网关中的API进行认证鉴权。

本章节介绍如何将校验函数封装成一个“自定义认证”,以及封装成自定义认证过程 中的操作注意事项。

5-1 前端自定义认证示意图

使用自定义认证调用API的流程如下图所示:

5-2 自定义认证调用 API

说明

自定义认证依赖函数服务。如果当前Region没有上线函数服务,则不支持使用自定义认证。

操作步骤

步骤1 在FunctionGraph中开发函数。

下面以python2.7语言为例,函数代码需要满足如下条件:

● 函数代码支持三种请求参数定义,格式为:

– Header中的请求参数:event["headers"]["参数名"]

– Query中的请求参数:event["queryStringParameters"]["参数名"]

– 您自定义的用户数据:event["user_data"]

● 函数代码获取的三种请求参数与API网关自定义认证中的参数关系如下所示:

– Header中的请求参数:对应自定义认证中参数位置为Header的身份来源,其 参数值在您调用使用该前端自定义认证的API时传入

– Query中的请求参数:对应自定义认证中参数位置为Query的身份来源,其参 数值在您调用使用该前端自定义认证的API时传入

– 您自定义的用户数据:对应自定义认证中的用户数据,其参数值在您创建自 定义认证时输入

● 函数的返回值不能大于1M,必须满足如下格式:

{ "statusCode":200,

"body": "{\"status\": \"allow\", \"context\": {\"user\": \"abc\"}}"

}

其中,body字段的内容为字符串格式,json解码之后为:

{ "status": "allow/deny",

def handler(event, context):

if event["headers"].get("test")=='abc':

resp = {

def handler(event, context):

if event["queryStringParameters"].get("test")=='abc':

resp = {

return json.dumps(resp)

用户数据定义代码示例:

# coding:utf-8 -*-import json

def handler(event, context):

if event.get("user_data")=='abc':

resp = {

return json.dumps(resp)

步骤2 测试函数。在测试事件的“事件模板”中选择“apig-event-template”,根据实际情 况修改后保存测试模板,单击“测试”。

执行结果为“成功”时,表示测试成功。

接下来您需要进入API网关界面创建前端自定义认证。

5-4 测试函数

----结束

后续操作

在自定义认证中已经创建完成用于前端自定义认证的Function API,下一步您需要进入 API网关中创建前端自定义认证。

6 创建用于后端自定义认证的函数

操作场景

如果您需要使用一种认证机制对接多个不同的外部认证系统,实现对于后端服务的保 护,您可以通过API网关中的后端自定义认证实现此功能。在使用后端自定义认证对后 端请求进行认证授权前,您需要先在FunctionGraph创建一个函数,通过函数定义您所 需的认证信息。函数作为自定义认证的后端函数,对API网关中的API进行认证授权。

6-1 后端自定义认证示意图

使用自定义认证调用API的流程如下图所示:

6-2 使用自定义认证调用 API

说明

自定义认证依赖函数服务。如果当前Region没有上线函数服务,则不支持使用自定义认证。

操作步骤

步骤1 在FunctionGraph中开发函数。

下面以python2.7为例,函数代码需要满足如下条件:

● 函数代码只支持您自定义的用户数据,且它的格式为:event["user_data"]。

● 函数代码获取的请求参数与API网关自定义认证中的参数关系为:函数请求参数中 的自定义用户数据对应API网关自定义认证中的用户数据,参数值在您创建API网 关自定义认证时输入,用户数据格式不限制,您可以自行指定。

● 函数的返回值不能大于1M,必须满足如下格式:

{ "statusCode":200,

"body": "{\"status\": \"allow\", \"context\": {\"user\": \"abc\"}}"

}

其中,body字段的内容为字符串格式,json解码之后为:

“context”字段为可选,只支持字符串类型键值对,键值不支持JSON对象或数 组。

context中的数据为您自定义的字段,认证通过后作为认证参数映射到API网关后 端参数中,其中context中的参数名称与系统参数名称必须完全一致,且区分大小 写。context中的参数名称必须以英文字母开头,支持英文大小写字母、数字、下 划线和中划线,且长度为1 ~ 32个字符。

如图6-3所示,后端认证通过后,context中的user的值abc映射到后端服务Header 位置的test参数中,并将其传递给API的后端服务。

6-3 认证参数映射到后端参数

用户数据定义代码示例:

# coding:utf-8 -*-import json

import base64

def handler(event, context):

token=base64.b64encode(event["user_data"]) resp = {

'statusCode': 200, 'body': json.dumps({

"status":"allow", "context":{

"token":token }

}) }

return json.dumps(resp)

步骤2 测试函数。在测试事件的“事件模板”中选择“空白模板”,内容为:

{"user_data": "123"}

根据实际情况修改后保存测试模板,单击“测试”。

执行结果为“成功”时,表示测试成功。

接下来您需要进入API网关界面创建后端自定义认证。

6-4 测试函数

----结束

后续操作

在自定义认证中已经创建完成用于后端自定义认证的Function API,下一步您需要进入 API网关中创建后端自定义认证。

7 对后端服务进行签名

7.1 Java

操作场景

使用Java语言进行后端服务签名时,您需要先获取SDK,然后导入工程,最后参考校 验后端签名示例校验签名是否一致。

本章节以IntelliJ IDEA 2018.3.5版本为例介绍。

前提条件

● 准备待用的签名密钥的Key和Secret。

● 已在控制台创建签名密钥,并绑定API,具体请参见创建并使用签名密钥。

● 已下载后端签名示例代码。

● 获取并安装IntelliJ IDEA,如果未安装,请至IntelliJ IDEA官方网站下载。

● 已安装Java Development Kit 1.8.111或以上版本,如果未安装,请至Oracle官方 下载页面下载。

导入工程

步骤1 打开IntelliJ IDEA,在菜单栏选择“File > New > Project from Existing Sources”,选 择解压后的“apigateway-backend-signature-demo\pom.xml”文件,单击“OK”。

7-1 Select File or Directory to Import

步骤2 保持默认设置,单击“Next > Next > Next > Next > Finish”,完成工程导入。

步骤3 在右侧Maven页签,双击“compile”进行编译。

7-2 编译工程

步骤4 右键单击BackendSignatureApplication,选择“Run”运行服务。

7-3 运行服务

“ApigatewaySignatureFilter.java”为示例代码,请根据实际情况修改参数后使用。

具体代码说明请参考校验后端签名示例。

----结束

校验后端签名示例

示例演示如何编写一个基于Spring boot的服务器,作为API的后端,并且实现一个 Filter,对API网关(即API管理)的请求做签名校验。

说明

API绑定签名密钥后,发给后端的请求中才会添加签名信息。

步骤1 编写一个Controller,匹配所有路径和方法,返回体为“Hello World!”。

// HelloController.java

@RestController

@EnableAutoConfiguration public class HelloController { @RequestMapping("/*") private String index() {

@WebFilter(filterName = "ApigatewaySignatureFilter", urlPatterns = "/*") public class ApigatewaySignatureFilter implements Filter {

private static Map<String, String> secrets = new HashMap<>();

static {

secrets.put("signature_key1", "signature_secret1");

secrets.put("signature_key2", "signature_secret2");

}

@Override

public void init(FilterConfig filterConfig) throws ServletException { }

@Override

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) { //签名校验代码

RequestWrapper request = new RequestWrapper((HttpServletRequest) servletRequest);

步骤4 使用正则表达式解析Authorization头,得到signingKey和signedHeaders。

private static final Pattern authorizationPattern = Pattern.compile("SDK-HMAC-SHA256\\s+Access=([^,]+),\

\s?SignedHeaders=([^,]+),\\s?Signature=(\\w+)");

...

}String signingKey = m.group(1);

String signingSecret = secrets.get(signingKey);

if (signingSecret == null) {

response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Signing key not found.");

return;

}String[] signedHeaders = m.group(2).split(";");

例如,Authorization头为:

SDK-HMAC-SHA256 Access=signature_key1, SignedHeaders=host;x-sdk-date, Signature=e11adf65a20d1b82c25419b5********8d0ba12fed1ceb13ed00

则解析的结果为:

signingKey=signature_key1 signedHeaders=host;x-sdk-date

步骤5 通过signingKey找到signingSecret,如果不存在signingKey,则返回认证失败。

String signingSecret = secrets.get(signingKey);

if (signingSecret == null) {

response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Signing key not found.");

return;

}

步骤6 新建一个Request对象,将请求method、url、query、signedHeaders对应的请求头放 入其中。判断是否需要设置body并设置。

需要读取body的条件为:不存在值为UNSIGNED-PAYLOAD的x-sdk-content-sha256 头。Request apiRequest = new DefaultRequest();

apiRequest.setHttpMethod(HttpMethodName.valueOf(request.getMethod()));

String url = request.getRequestURL().toString();

String queryString = request.getQueryString();

try {

apiRequest.setEndpoint((new URL(url)).toURI());

Map<String, String> parametersmap = new HashMap<>();

if (null != queryString && !"".equals(queryString)) { String[] parameterarray = queryString.split("&");

for (String p : parameterarray) {

parametersmap.put(URLDecoder.decode(key, "UTF-8"), URLDecoder.decode(value, "UTF-8"));

}

apiRequest.setParameters(parametersmap); //set query }

} catch (URISyntaxException e) { e.printStackTrace();

}

boolean needbody = true;

String dateHeader = null;

for (int i = 0; i < signedHeaders.length; i++) {

String headerValue = request.getHeader(signedHeaders[i]);

if (headerValue == null || headerValue.length() == 0) {

((HttpServletResponse) response).sendError(HttpServletResponse.SC_UNAUTHORIZED, "signed header" + signedHeaders[i] + " not found.");

} else {

apiRequest.addHeader(signedHeaders[i], headerValue);//set header if (signedHeaders[i].toLowerCase().equals("x-sdk-content-sha256") &&

headerValue.equals("UNSIGNED-PAYLOAD")) { needbody = false;

}

if (signedHeaders[i].toLowerCase().equals("x-sdk-date")) {

dateHeader = headerValue;

} } }

if (needbody) {

apiRequest.setContent(new ByteArrayInputStream(request.getBody())); //set body }

步骤7 校验签名是否过期。从X-Sdk-Date头中取出时间,判断与服务器时间是否相差在15分 钟以内。如果signedHeaders中不包含X-Sdk-Date,也返回认证失败。

private static final DateTimeFormatter timeFormatter =

DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss'Z'").withZoneUTC();

...

if (dateHeader == null) {

response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Header x-sdk-date not found.");

return;

}long date = timeFormatter.parseMillis(dateHeader);

long duration = Math.abs(DateTime.now().getMillis() - date);

if (duration > 15 * 60 * 1000) {

response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Signature expired.");

return;

}

步骤8 将Authorization头也放入Request对象中,调用verify方法校验请求签名。如果校验通 过,则执行下一个filter,否则返回认证失败。

DefaultSigner signer = (DefaultSigner) SignerFactory.getSigner();

boolean verify = signer.verify(apiRequest, new BasicCredentials(signingKey, signingSecret));

if (verify) {

chain.doFilter(request, response);

} else {

response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "verify authroization failed.");

}

步骤9 运行服务器,验证代码正确性。下面示例使用JavaScript SDK中的html签名工具生成 签名。

填入如图所示字段后,单击“Send request”,复制生成的curl命令,并在命令行中执 行,服务器返回“Hello World!”。

如果使用错误的Key和Secret访问,服务器返回401认证不通过。

----结束

7.2 Python

操作场景

使用Python语言进行后端服务签名时,您需要先获取SDK,然后导入工程,最后参考 校验后端签名示例校验签名是否一致。

本章节以IntelliJ IDEA 2018.3.5版本为例介绍。

准备环境

● 准备待用的签名密钥的Key和Secret。

● 已在控制台创建签名密钥,并绑定API,具体请参见创建并使用签名密钥。

● 请登录API网关控制台,参考《用户指南》的“SDK”章节,进入SDK页面并下载 SDK。或直接下载SDK的最新版本。

● 获取并安装Python安装包(可使用2.7或3.X),如果未安装,请至Python官方下 载页面下载。

● 获取并安装IntelliJ IDEA,如果未安装,请至IntelliJ IDEA官方网站下载。

● 已在IntelliJ IDEA中安装Python插件,如果未安装,请按照图7-4所示安装。

7-4 安装 Python 插件

导入工程

步骤1 打开IntelliJ IDEA,在菜单栏选择“File > New > Project”。

步骤1 打开IntelliJ IDEA,在菜单栏选择“File > New > Project”。

相關文件