aws(学习笔记第四十课) image-content-search
- 使用
SQS
+Lambda
集成 - 数据库(
Aurora Serverless
) -
Cognito
(用户管理) -
rekognition
(图像解析)
学习内容:
- 使用
SQS
+Lambda
+Aurora Serverless
+Cognito
+rekognition
1. 整体架构
1.1 代码链接
1.2 关键架构流程
- 用户上传图像 → S3触发Lambda → 图像分析 → 结果存入数据库
- 前端通过API Gateway查询数据库(需Cognito认证)
- 事件总线协调异步任务(如分析完成后触发存储操作)。
1.3 upload
图像文件的动作

1.4 search
图像文件的动作

2. 代码解析
2.1 yml
文件配置详细设定
2.1.1 yml
文件
这里配置了Environment
,Author
,Region
等配置,比起写入cdk.py
的python
代码中,这里将配置数据写入yml
文件中会更加清晰。
yaml
Environment: Development
Author: Mohsen
Region: eu-central-1
ProjectName: ImageContentSearch
DeadLetterQueue:
MaxReceiveCount: 3
Cognito:
SelfSignUp: True
DomainPrefix: image-content-search
AllowedOAuthScopes:
- phone
- email
- openid
- profile
Database:
Name: images_labels
DeletionProtection: False
Scaling:
AutoPause: True
Min: 2
Max: 8
SecondsToAutoPause: 1800
Functions:
DefaultSignedUrlExpirySeconds: "3600"
DefaultMaxApiCallAttempts: "5"
2.1.2 yml
文件文件解析
python
with open("stack/config.yml", 'r') as stream:
configs = yaml.safe_load(stream)
# for example, use configs in image_data_function
image_data_function = Function(self, "ICS_IMAGE_DATA",
function_name="ICS_IMAGE_DATA",
runtime=Runtime.PYTHON_3_7,
timeout=Duration.seconds(5),
role=image_data_function_role,
environment={
"DEFAULT_MAX_CALL_ATTEMPTS": configs["Functions"]["DefaultMaxApiCallAttempts"],
"CLUSTER_ARN": database_cluster_arn,
"CREDENTIALS_ARN": database_secret.secret_arn,
"DB_NAME": database.database_name,
"REGION": Aws.REGION
},
handler="main.handler",
code=Code.from_asset("./src/imageData")
)
2.2 创建s3 bucket
python
### S3 core
images_S3_bucket = _s3.Bucket(self, "ICS_IMAGES")
images_S3_bucket.add_cors_rule(
allowed_methods=[_s3.HttpMethods.POST],
allowed_origins=["*"] # add API gateway web resource URL
)
这里,需要从API gateway
的domain
进行跨域访问S3 bucket
的AWS
的url
,因此需要CORS Cross-Origin Resource Share
,是浏览器的一种安全机制,用于控制不同源(协议+域名+端口)之间的资源访问。
在之前的文章中介绍过。spring boot(学习笔记第五课) 自定义错误页,CORS(跨域支持)
2.3 创建API Gateway
python
### api gateway core
api_gateway = RestApi(self, 'ICS_API_GATEWAY', rest_api_name='ImageContentSearchApiGateway')
api_gateway_resource = api_gateway.root.add_resource(configs["ProjectName"])
api_gateway_landing_page_resource = api_gateway_resource.add_resource('web')
api_gateway_get_signedurl_resource = api_gateway_resource.add_resource('signedUrl')
api_gateway_image_search_resource = api_gateway_resource.add_resource('search')
api_gateway_resource
作为父resouce
。api_gateway_landing_page_resource
作为子resource
,作为文件上传的表示页面。api_gateway_landing_page_resource
作为子resource
,作为文件上传S3 bucket
的请求url
。api_gateway_image_search_resource
作为子resource
,作为文件分析结果的页面。
2.4 创建文件上传的表示页面
2.4.1 创建文件上传的api_gateway_resource
的lambda
函数
python
### landing page function
get_landing_page_function = Function(self, "ICS_GET_LANDING_PAGE",
function_name="ICS_GET_LANDING_PAGE",
runtime=Runtime.PYTHON_3_7,
handler="main.handler",
code=Code.from_asset("./src/landingPage"))
2.4.2 配置文件上传的LambdaIntegration
python
get_landing_page_integration = LambdaIntegration(
get_landing_page_function,
proxy=True,
integration_responses=[IntegrationResponse(
status_code='200',
response_parameters={
'method.response.header.Access-Control-Allow-Origin': "'*'"
}
)])
注意,这里配置method.response.header.Access-Control-Allow-Origin
以便允许其他domain
过来的跨域的访问。但是,如果是生产环境,需要将*
换成特定的domain
。
2.4.3 配置文件上传的API Gateway Method
python
api_gateway_landing_page_resource.add_method('GET', get_landing_page_integration,
method_responses=[MethodResponse(
status_code='200',
response_parameters={
'method.response.header.Access-Control-Allow-Origin': True
}
)])
2.4.4 配置文件上传的页面代码

2.4.4.1 python
的lambda handler
\src\landingPage\main.py
python
# this function
# gets the simple html page
# updates the login page and logout page address
# returns the content
def handler(event, context):
login_page = event["headers"]["Referer"]
return {
'statusCode': 200,
'headers': {
'Content-Type': 'text/html'
},
'body': file_get_contents("index.html").replace('###loginPage###', login_page)
}
def file_get_contents(filename):
with open(filename) as f:
return f.read()
这里,直接将html
的文件打开,进行返回
2.4.4.2 html
的页面代码
\src\landingPage\index.html
html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body{font-family:Arial}.tab{overflow:hidden;border:1px solid #ccc;background-color:#f1f1f1}.tab button{background-color:inherit;float:left;border:none;outline:0;cursor:pointer;padding:14px 16px;transition:.3s;font-size:17px}.tab button:hover{background-color:#ddd}.tab button.active{background-color:#ccc}.tabcontent{display:none;padding:6px 12px;-webkit-animation:fadeEffect 1s;animation:fadeEffect 1s}@-webkit-keyframes fadeEffect{from{opacity:0}to{opacity:1}}@keyframes fadeEffect{from{opacity:0}to{opacity:1}}
input[type=text],select{width:30%;padding:12px 20px;margin:8px 0;display:inline-block;border:1px solid #ccc;border-radius:4px;box-sizing:border-box}.submit[type=submit]{width:20%;background-color:#4caf50;color:#fff;padding:14px 20px;margin:8px 0;border:none;border-radius:4px;cursor:pointer}input[type=submit]:hover{background-color:#45a049}.div{border-radius:5px;background-color:#f2f2f2;padding:20px}
table{border-collapse:collapse;table-layout: fixed;width:100%}td,th{text-align:left;padding:8px;word-wrap:break-word;}tr:nth-child(even){background-color:#f2f2f2}
</style>
<script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>
<script>
var authData = window.location.hash.substring(1);
var idToken = authData.split('&').find((rec) => rec.split('=')[0] == 'id_token').split('=')[1]
var getSignedUrlEndpoint = window.location.href.split('#')[0].replace('web', 'signedUrl')
var searchImageEndpoint = window.location.href.split('#')[0].replace('web', 'search')
var loginPage = '###loginPage###';
var logoutPage = loginPage.replace('login', 'logout');
function logout() {
window.location.replace(logoutPage);
}
function getSignedUrl() {
$.ajax({
url: getSignedUrlEndpoint,
headers: { 'Authorization': idToken },
type: "GET",
contentType: 'application/json; charset=utf-8',
success: function (result) {
console.log(result);
$("#upload_image_form").attr('action', result.url);
$('input[name="key"]').val(result.fields.key);
$('input[name="X-Amz-Credential"]').val(result.fields['x-amz-credential']);
$('input[name="X-Amz-Algorithm"]').val(result.fields['x-amz-algorithm']);
$('input[name="X-Amz-Date"]').val(result.fields['x-amz-date']);
$('input[name="x-amz-security-token"]').val(result.fields['x-amz-security-token']);
$('input[name="Policy"]').val(result.fields.policy);
$('input[name="X-Amz-Signature"]').val(result.fields['x-amz-signature']);
},
error: function (error) {
console.log(error);
if (error.status == 401) {logout();}
}
});
}
function listImagesByLabel(outputTab, label, language, country) {
console.log('Finding images with label: ' + label);
var formData = language ? {label, language, country} : {label}
$.ajax({
url: searchImageEndpoint,
headers: { 'Authorization': idToken },
type: "POST",
data: {...formData, 'source': 'API'},
contentType: 'application/json; charset=utf-8',
success: function (results) {
console.log(results);
$(outputTab + " tr").remove();
$(outputTab + " th").remove();
if (results) {
$(outputTab).append( '<tr><th>Image ID</th></tr>' );
results.forEach(item => {
$(outputTab).append( '<tr><td>' + item.id + '</th></tr>' );
});
}
},
error: function (error) {
console.log(error.responseText, error.status);
if (error.status == 401) {logout();}
}
});
}
$(document).ready(function () {
if (window.location.hash) {
// getSignedUrl();
} else {
console.log('Authorization information from cognito is not found!');
}
});
function submitSearchQuery() {
event.preventDefault();
var language = $('#language').val();
var country = $('#country').val();
var label = $('input[name=label]').val();
listImagesByLabel('#search_image_result', label, language, country);
}
function openTab(evt, tabName) {
$("#upload_result").text('');
$("#upload_result").css("color", "black");
$("#file_select").val('');
if (tabName == 'upload') {
getSignedUrl();
}
if (tabName == 'report') {
listImagesByLabel('#report_image_result', 'offensive');
}
var i, tabcontent, tablinks;
tabcontent = document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
document.getElementById(tabName).style.display = "block";
evt.currentTarget.className += " active";
}
function submitFileUpload() {
event.preventDefault();
var formData = new FormData();
var selectedFile = $('input[name="file"]')[0]
$('#upload_image_form *').filter(':input').filter(":hidden").each(function(k, v){
formData.append(v.name, v.defaultValue);
});
formData.append("file", selectedFile.files[0]);
$.ajax({
url: $("#upload_image_form").attr('action'),
type: 'POST',
data: formData,
success: function (data) {
$("#upload_result").text('The file has been successfully uploaded!');
$("#upload_result").css("color", "green");
getSignedUrl();
},
error: function(xhr, textStatus, errorThrown){
$("#upload_result").text('The file upload failed!');
$("#upload_result").css("color", "red");
console.log(textStatus);
console.log(errorThrown);
},
cache: false,
contentType: false,
processData: false
});
};
</script>
</head>
<body>
<div style="width: 50%; margin-left: 25%;">
<div class="tab" style="margin-top: 10px;">
<button class="tablinks" onclick="openTab(event, 'upload')" id="default_tab">Upload</button>
<button class="tablinks" onclick="openTab(event, 'search')">Search</button>
<button class="tablinks" onclick="openTab(event, 'report')">Report</button>
<button class="tablinks" onclick="logout()" style="float: right;">Logout</button>
</div>
<div id="upload" class="tabcontent">
<h3>Upload Image</h3>
<p>Select image to upload:</p>
<form id="upload_image_form" method="post" enctype="multipart/form-data">
<input type="hidden" name="key"/><br />
<input type="hidden" name="X-Amz-Credential"/>
<input type="hidden" name="X-Amz-Algorithm"/>
<input type="hidden" name="X-Amz-Date"/>
<input type="hidden" name="x-amz-security-token"/>
<input type="hidden" name="Policy"/>
<input type="hidden" name="X-Amz-Signature"/>
<input type="file" id="file_select" name="file"/> <br />
<input type="submit" class="submit" value="Upload" onclick="submitFileUpload()"/>
</form>
<p id="upload_result"></p>
</div>
<div id="search" class="tabcontent">
<h3>Search Labels</h3>
<form id="search_image_form" method="post">
<label >Language:</label>
<select name="language" id="language">
<option value="en">English</option>
<option value="tr">Turkish</option>
<option value="nl">Dutch</option>
</select>
<br />
<label >Country:</label>
<select name="country" id="country">
<option value="nl">Netherlands</option>
</select>
<br />
<label >Label to search:</label>
<input type="text" name="label"/><br />
<input class="submit" type="submit" value="Search" onclick="submitSearchQuery()"/>
</form>
<table id="search_image_result"></table>
</div>
<div id="report" class="tabcontent">
<h3>Report of offensive photos</h3>
<table id="report_image_result"></table>
</div>
</div>
<script>
document.getElementById("default_tab").click();
</script>
</body>
</html>
2.5 配置cognito
安全认证
python
### cognito
required_attribute = _cognito.StandardAttribute(required=True)
users_pool = _cognito.UserPool(self, "ICS_USERS_POOL",
auto_verify=_cognito.AutoVerifiedAttrs(email=True), #required for self sign-up
standard_attributes=_cognito.StandardAttributes(email=required_attribute), #required for self sign-up
self_sign_up_enabled=configs["Cognito"]["SelfSignUp"])
user_pool_app_client = _cognito.CfnUserPoolClient(self, "ICS_USERS_POOL_APP_CLIENT",
supported_identity_providers=["COGNITO"],
allowed_o_auth_flows=["implicit"],
allowed_o_auth_scopes=configs["Cognito"]["AllowedOAuthScopes"],
user_pool_id=users_pool.user_pool_id,
callback_urls=[api_gateway.url_for_path('/web')],
allowed_o_auth_flows_user_pool_client=True,
explicit_auth_flows=["ALLOW_REFRESH_TOKEN_AUTH"])
这里表示/web
需要认证,并且认证之后url
将重定向到/web
。
2.6 创建signedURL
的API Gateway
2.6.1 创建signedURL
的API Gateway
python
### get signed URL function
get_signedurl_function = Function(self, "ICS_GET_SIGNED_URL",
function_name="ICS_GET_SIGNED_URL",
environment={
"ICS_IMAGES_BUCKET": images_S3_bucket.bucket_name,
"DEFAULT_SIGNEDURL_EXPIRY_SECONDS": configs["Functions"]["DefaultSignedUrlExpirySeconds"]
},
runtime=Runtime.PYTHON_3_7,
handler="main.handler",
code=Code.from_asset("./src/getSignedUrl"))
get_signedurl_integration = LambdaIntegration(
get_signedurl_function,
proxy=True,
integration_responses=[IntegrationResponse(
status_code='200',
response_parameters={
'method.response.header.Access-Control-Allow-Origin': "'*'",
}
)])
api_gateway_get_signedurl_authorizer = CfnAuthorizer(self, "ICS_API_GATEWAY_GET_SIGNED_URL_AUTHORIZER",
rest_api_id=api_gateway_get_signedurl_resource.api.rest_api_id,
name="ICS_API_GATEWAY_GET_SIGNED_URL_AUTHORIZER",
type="COGNITO_USER_POOLS",
identity_source="method.request.header.Authorization",
provider_arns=[users_pool.user_pool_arn])
get_signedurl_method = api_gateway_get_signedurl_resource.add_method('GET', get_signedurl_integration,
authorization_type=AuthorizationType.COGNITO,
method_responses=[MethodResponse(
status_code='200',
response_parameters={
'method.response.header.Access-Control-Allow-Origin': True,
}
)])
signedurl_custom_resource = typing.cast("aws_cloudformation.CfnCustomResource", get_signedurl_method.node.find_child('Resource'))
signedurl_custom_resource.add_property_override('AuthorizerId', api_gateway_get_signedurl_authorizer.ref)
images_S3_bucket.grant_put(get_signedurl_function, objects_key_pattern="new/*")
2.6.2 创建signedURL
的API Gateway
处理的lambda
这里,从前端传递来的文件被put
到S3 bucket
。
python
import json
import boto3
import logging
import os
import time
import hashlib
from botocore.exceptions import ClientError
images_bucket = os.environ['ICS_IMAGES_BUCKET']
default_signedurl_expiry_seconds = os.environ['DEFAULT_SIGNEDURL_EXPIRY_SECONDS']
# this function
# creates a pre-sighned URL for uploading image to S3 and returns it
def handler(event, context):
uniquehash = hashlib.sha1("{}".format(time.time_ns()).encode('utf-8')).hexdigest()
result = create_presigned_post(images_bucket, "new/{}/{}".format(uniquehash[:2],uniquehash))
return {
'statusCode': 200,
'headers': {
'Content-Type': 'application/json; charset=UTF-8'
},
'body': json.dumps(result)
}
def create_presigned_post(bucket_name, object_name, fields=None, conditions=None, expiration=default_signedurl_expiry_seconds):
s3_client = boto3.client('s3')
try:
response = s3_client.generate_presigned_post(bucket_name,
object_name,
Fields=fields,
Conditions=conditions,
ExpiresIn=int(expiration)
)
except ClientError as e:
logging.error(e)
return None
return response
2.7 监视S3 bucket
的lambda
2.7.1 监视架构

2.7.2 创建lmabda
python
### image massage function
image_massage_function = Function(self, "ICS_IMAGE_MASSAGE",
function_name="ICS_IMAGE_MASSAGE",
timeout=Duration.seconds(6),
runtime=Runtime.PYTHON_3_7,
environment={"ICS_IMAGE_MASSAGE": image_queue.queue_name},
handler="main.handler",
code=Code.from_asset("./src/imageMassage"))
images_S3_bucket.grant_write(image_massage_function, "processed/*")
images_S3_bucket.grant_delete(image_massage_function, "new/*")
images_S3_bucket.grant_read(image_massage_function, "new/*")
new_image_added_notification = _s3notification.LambdaDestination(image_massage_function)
images_S3_bucket.add_event_notification(_s3.EventType.OBJECT_CREATED,
new_image_added_notification,
_s3.NotificationKeyFilter(prefix="new/")
)
image_queue.grant_send_messages(image_massage_function)
2.7.2 S3 bucket
监视的lmabda
代码
python
def handler(event, context):
s3 = boto3.resource('s3')
for record in event['Records']:
newKey = record['s3']['object']['key']
bucket = record['s3']['bucket']['name']
name = bucket.split("/")[-1]
localfile = "/tmp/{}".format(name)
# download the file
new_key_obj = s3.Object(bucket, newKey)
new_key_obj.download_file(localfile)
# calc hash
image_SHA1 = getSha1(localfile)
# check if not exist
processed_key = "processed/{}/{}".format(image_SHA1[:2], image_SHA1)
key_is_processed = isS3ObjectExist(bucket, processed_key)
if key_is_processed: continue
# add to the queue
message = json.dumps({
"image": processed_key,
"original_key": newKey,
"original_last_modified": new_key_obj.last_modified,
"etag": new_key_obj.e_tag
}, default=str)
queue = sqs.get_queue_by_name(QueueName=queue_name)
response = queue.send_message(MessageBody=message)
logger.info("Message {} has been sent.".format(response.get('MessageId')))
#move the image
s3.Object(bucket, processed_key).copy_from(CopySource="{}/{}".format(bucket,newKey))
new_key_obj.delete()
# delete local file
os.remove(localfile)
return True
def isS3ObjectExist(bucket, key):
s3 = boto3.resource('s3')
try:
s3.Object(bucket,key)
return False
except botocore.exceptions.ClientError as e:
if e.response['Error']['Code'] == "404":
return True
else:
raise e
def getSha1(filepath):
sha1 = hashlib.sha1()
with open(filepath, 'rb') as f:
while True:
data = f.read(65536) # read in 64kb chunks
if not data: break
sha1.update(data)
return sha1.hexdigest()
2.8 创建lambda
对图像进行分析
2.8.1 图像分析架构

2.8.1 图像分析lambda
函数
python
def handler(event, context):
for record in event['Records']:
# receiptHandle = record['receiptHandle']
body = record['body']
message = json.loads(body)
bucket = os.environ['ICS_IMAGES_BUCKET']
key = message['image']
# original_key = message['original_key']
# original_last_modified = message['original_last_modified']
# etag = message['etag']
logger.info('Processing {}.'.format(key))
detected_labels = rekognition_client.detect_labels(
Image={'S3Object': {'Bucket': bucket, 'Name': key}},
MaxLabels=20,
MinConfidence=85)
detected_unsafe_contents = rekognition_client.detect_moderation_labels(
Image={'S3Object': {'Bucket': bucket, 'Name': key}})
object_labels = []
for l in detected_labels['Labels']:
object_labels.append(l['Name'].lower()) # add objects in image
for l in detected_unsafe_contents['ModerationLabels']:
if ('offensive' not in object_labels): object_labels.append("offensive") #label image as offensive
object_labels.append(l['Name'].lower())
image_id = key.split("/")[-1]
response = events_client.put_events(
Entries=[
{
'Source': "EventBridge",
'Resources': [
context.invoked_function_arn,
],
'DetailType': 'images_labels',
'Detail': json.dumps({"labels": object_labels, "image_id": image_id}),
'EventBusName': event_bus_name
},
]
)
if response["FailedEntryCount"] == 1:
raise Exception(f'Failed entry observed. Count: {response["Entries"]}')
2.9 创建图像分析数据保存的数据库
2.9.1 创建数据库的密码
python
### database
database_secret = _secrets_manager.Secret(self, "ICS_DATABASE_SECRET",
secret_name="rds-db-credentials/image-content-search-rds-secret",
generate_secret_string=_secrets_manager.SecretStringGenerator(
generate_string_key='password',
secret_string_template='{"username": "dba"}',
exclude_punctuation=True,
exclude_characters='/@\" \\\'',
require_each_included_type=True
)
)
2.9.2 创建数据库
python
database = _rds.CfnDBCluster(self, "ICS_DATABASE",
engine=_rds.DatabaseClusterEngine.aurora_mysql(version=_rds.AuroraMysqlEngineVersion.VER_5_7_12).engine_type,
engine_mode="serverless",
database_name=configs["Database"]["Name"],
enable_http_endpoint=True,
deletion_protection=configs["Database"]["DeletionProtection"],
master_username=database_secret.secret_value_from_json("username").to_string(),
master_user_password=database_secret.secret_value_from_json("password").to_string(),
scaling_configuration=_rds.CfnDBCluster.ScalingConfigurationProperty(
auto_pause=configs["Database"]["Scaling"]["AutoPause"],
min_capacity=configs["Database"]["Scaling"]["Min"],
max_capacity=configs["Database"]["Scaling"]["Max"],
seconds_until_auto_pause=configs["Database"]["Scaling"]["SecondsToAutoPause"]
),
)
2.9.3 将数据库密码和数据库绑定attachment
python
database_cluster_arn = "arn:aws:rds:{}:{}:cluster:{}".format(Aws.REGION, Aws.ACCOUNT_ID, database.ref)
secret_target = _secrets_manager.CfnSecretTargetAttachment(self,"ICS_DATABASE_SECRET_TARGET",
target_type="AWS::RDS::DBCluster",
target_id=database.ref,
secret_id=database_secret.secret_arn
)
secret_target.node.add_dependency(database)
2.10 创建数据库的lambda function
2.10.1 创建数据库访问role
python
### database function
image_data_function_role = _iam.Role(self, "ICS_IMAGE_DATA_FUNCTION_ROLE",
role_name="ICS_IMAGE_DATA_FUNCTION_ROLE",
assumed_by=_iam.ServicePrincipal("lambda.amazonaws.com"),
managed_policies=[
_iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaVPCAccessExecutionRole"),
_iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaBasicExecutionRole"),
_iam.ManagedPolicy.from_aws_managed_policy_name("AmazonRDSDataFullAccess")
]
)
2.10.2 创建image_data_function

python
image_data_function = Function(self, "ICS_IMAGE_DATA",
function_name="ICS_IMAGE_DATA",
runtime=Runtime.PYTHON_3_7,
timeout=Duration.seconds(5),
role=image_data_function_role,
environment={
"DEFAULT_MAX_CALL_ATTEMPTS": configs["Functions"]["DefaultMaxApiCallAttempts"],
"CLUSTER_ARN": database_cluster_arn,
"CREDENTIALS_ARN": database_secret.secret_arn,
"DB_NAME": database.database_name,
"REGION": Aws.REGION
},
handler="main.handler",
code=Code.from_asset("./src/imageData")
)
2.10.3 创建image search function

python
image_search_integration = LambdaIntegration(
image_data_function,
proxy=True,
integration_responses=[IntegrationResponse(
status_code='200',
response_parameters={
'method.response.header.Access-Control-Allow-Origin': "'*'",
}
)])
api_gateway_image_search_authorizer = CfnAuthorizer(self, "ICS_API_GATEWAY_IMAGE_SEARCH_AUTHORIZER",
rest_api_id=api_gateway_image_search_resource.api.rest_api_id,
name="ICS_API_GATEWAY_IMAGE_SEARCH_AUTHORIZER",
type="COGNITO_USER_POOLS",
identity_source="method.request.header.Authorization",
provider_arns=[users_pool.user_pool_arn])
search_integration_method = api_gateway_image_search_resource.add_method('POST', image_search_integration,
authorization_type=AuthorizationType.COGNITO,
method_responses=[MethodResponse(
status_code='200',
response_parameters={
'method.response.header.Access-Control-Allow-Origin': True,
}
)])
search_integration_custom_resource = typing.cast("aws_cloudformation.CfnCustomResource", search_integration_method.node.find_child('Resource'))
search_integration_custom_resource.add_property_override('AuthorizerId', api_gateway_image_search_authorizer.ref)

2.10.4 创建image db
的schema
python
### custom resource
lambda_provider = Provider(self, 'ICS_IMAGE_DATA_PROVIDER',
on_event_handler=image_data_function
)
CustomResource(self, 'ICS_IMAGE_DATA_RESOURCE',
service_token=lambda_provider.service_token,
pascal_case_properties=False,
resource_type="Custom::SchemaCreation",
properties={
"source": "Cloudformation"
}
)

2.10.5 创建image db
的保存lambda
image_analyzer_function
保存分析结果到event_bus
之中,这里继续将event_rule.add_target(_event_targets.LambdaFunction(image_data_function))
,之后image_data_function
会将数据保存到数据库。
python
### event bridge
event_bus = _events.EventBus(self, "ICS_IMAGE_CONTENT_BUS", event_bus_name="ImageContentBus")
event_rule = _events.Rule(self, "ICS_IMAGE_CONTENT_RULE",
rule_name="ICS_IMAGE_CONTENT_RULE",
description="The event from image analyzer to store the data",
event_bus=event_bus,
event_pattern=_events.EventPattern(resources=[image_analyzer_function.function_arn]),
)
event_rule.add_target(_event_targets.LambdaFunction(image_data_function))

3 执行cdk
TODO