使用 API Gateway 和 Lambda 验证 reCAPTCHA
对于 S3 静态站点上的无服务器 SPA 站点上的联系表单,我将 AngularJS 与“angular-recaptcha”服务 (https://github.com/VividCortex/angular-recaptcha) 结合使用,尽管您可以使用任何方式获取和发布 recaptcha 值。
在后端,您可以使用调用 Lambda 函数的 API Gateway 来验证 recaptcha 值并执行某些操作。使用 NodeJS 和 Recaptcha2 (https://www.npmjs.com/package/recaptcha2) 来验证令牌。
var reCAPTCHA = require('recaptcha2')
module.exports.sendemail = (event, context, callback) => {
// parse the data that was sent from API Gateway
var eventData = JSON.parse(event.body);
// Prepare the recaptcha connection to Google
var recaptcha = new reCAPTCHA({
siteKey: process.env.RECAPTCHA_KEY,
secretKey: process.env.RECAPTCHA_SECRET
})
// Validate the recaptcha value
recaptcha.validate(eventData.recaptcha)
.then(function(){
// validated ok
console.log("ReCaptcha Valid")
... DO STUFF HERE ...
})
.catch(function(errorCodes){
// invalid recaptcha
console.log("ReCaptcha Not Valid")
// translate error codes to human readable text
console.log(recaptcha.translateErrors(errorCodes));
// send a fail message with cors headers back to the UI
var response = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
},
body: JSON.stringify({"message":"Error: Invalid Recaptcha"})
}
callback(null, response);
});
};
使用 Handlebars 和 SES 的模板电子邮件示例
作为奖励,这里有一些我重复使用的代码,用于使用 html/文本模板发送电子邮件:
- 把手用于向模板 SES 注入值以发送电子邮件。
- 确保您已使用您的域名设置 SES,并允许 Lambda 访问“ses:SendEmail”和“ses:SendEmailRaw”。
- 在部署函数时添加环境变量,这样可以使代码可重用,并保持源代码的秘密。
- 我强烈建议使用无服务器框架来部署您的无服务器应用程序。 https://serverless.com
对我来说是一种享受:)
'use strict';
var AWS = require('aws-sdk');
var ses = new AWS.SES();
var reCAPTCHA = require('recaptcha2')
var fs = require('fs');
var Handlebars = require('handlebars');
module.exports.sendemail = (event, context, callback) => {
// parse the data that was sent from API Gateway
var eventData = JSON.parse(event.body);
// Prepare the recaptcha connection to Google
var recaptcha = new reCAPTCHA({
siteKey: process.env.RECAPTCHA_KEY,
secretKey: process.env.RECAPTCHA_SECRET
})
// Validate the recaptcha value
recaptcha.validate(eventData.recaptcha)
.then(function(){
// validated ok
console.log("reCAPTCHA Valid")
// Read the HTML template from the package root
fs.readFile('./contact/email_template.html', function (err, emailHtmlTemplate) {
if (err) {
console.log("Unable to load HTML Template");
throw err;
}
// Read the TEXT template from the package root
fs.readFile('./contact/email_template.txt', function (err, emailTextTemplate) {
if (err) {
console.log("Unable to load TEXT Template");
throw err;
}
// Gather data to be injected to the templates
var emailData = {
"websiteaddress": process.env.WEBSITEADDRESS,
"websitename": process.env.WEBSITENAME,
"content": null,
"email": process.env.EMAIL_TO,
"event": eventData
};
// Use Handlebars to compile the template and inject values into the title (used in subject and body of email)
var templateTitle = Handlebars.compile(process.env.EMAIL_TITLE);
var titleText = templateTitle(emailData);
console.log(titleText);
// Add title to the values object
emailData.title = titleText;
// Use Handlebars to compile email plaintext body
var templateText = Handlebars.compile(emailTextTemplate.toString());
var bodyText = templateText(emailData);
console.log(bodyText);
// Use Handlebars to compile email html body
var templateHtml = Handlebars.compile(emailHtmlTemplate.toString());
var bodyHtml = templateHtml(emailData);
console.log(bodyHtml);
// Prepare the SES payload
var params = {
Destination: {
ToAddresses: [
process.env.EMAIL_TO
]
},
Message: {
Body: {
Text: {
Data: bodyText,
Charset: 'UTF-8'
},
Html: {
Data: bodyHtml
},
},
Subject: {
Data: titleText,
Charset: 'UTF-8'
}
},
Source: process.env.EMAIL_FROM
}
console.log(JSON.stringify(params,null,4));
// Send SES Email
ses.sendEmail(params, function(err,data){
if(err) {
console.log(err,err.stack); // error
// Handle SES send errors
var response = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
},
body: JSON.stringify({"message":"Error: Unable to Send Message"})
}
callback(null, response);
}
else {
console.log(data); // success
// SES send was successful
var response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
},
body: JSON.stringify({"message":"Message Sent"})
}
callback(null, response);
}
});
}); //end of load text template
}); //end of load html template
})
.catch(function(errorCodes){
// invalid recaptcha
console.log("reCAPTCHA Not Valid")
// translate error codes to human readable text
console.log(recaptcha.translateErrors(errorCodes));
// send a fail message with cors headers back to the UI
var response = {
statusCode: 500,
headers: {
"Access-Control-Allow-Origin" : "*",
"Access-Control-Allow-Credentials" : true
},
body: JSON.stringify({"message":"Error: Invalid Recaptcha"})
}
callback(null, response);
});
};
编辑:修正语法错误