.net 8 C# 集成 AWS Cognito SMS/Email 注册与登录
本文主要分为三个部分:
1、描述 cognito 涉及的专业术语 以及 交互流程
2、.net 集成的代码
3、感想
* 阅读提示 :鼠标悬停在 章节标题 上可见 文章目录
1. Cognito 概念
1.1 关键词
进入 Amazon Cognito,会先看到 user pool 的列表

|
cognito
|
亚马逊(Amazon)云 提供的一种用户管理服务,简化用户注册、登录和授权、鉴权相关的服务操作。
可以在 cognito 上创建用户池,管理用户注册、登录和鉴权相关的问题;
可以创建 identity pool 对用户进行授权相关的约束;
支持多种身份验证方式,例如 用户 / 密码 登录,社交帐号( Facebook,Google 等)登录,企业身份供应商
|
|
user pool
|
用户池,多租户 / 不同的服务供应商,拥有自己的用户群体;
用户池支持用户注册、登录、鉴权、账号恢复等。
|
|
identity pool
|
资格授权池,可以提供一些 AWS 的资格认证到通过验证的用户上
|
|
app client
|
用户池所关联的应用服务端,必须要配置到相关的用户池上才允许访问该用户池
|
选定一个用户池,可以查看该用户池的信息,左侧栏见其 功能 / 配置

user pool 功能 / 配置 目录列表
* 为了降低描述的复杂度,此处仅做最小配置展开
* 加粗为需要重点关注;此处不展开 IdentityPool 以及 userPool.Security 和 userPool.Branding
|
Seconcd |
Third |
Description |
Remark |
|
|
User Pool |
Overview |
用户池的基本信息 |
集成时需要找到这个用户池的 ID、ARN 等信息 |
|
|
Applications |
app client |
配置可访问该用户池的应用端信息 |
在此处可以限制一些读写的权限 |
|
|
User Management |
Users |
用户池里面的每个用户 |
相当于用户表,可以自定义用户属性 custom user attribute |
|
|
Groups |
用户分组,主要用于指定某个组内的用户可以享有某些权限 |
按需求来,可选配置 |
||
|
Authentication |
Authentication methods |
用户验证方式的配置 |
可以在此处配置密码验证 或 通过短信验证 或 通过邮箱验证 |
|
|
Sign-in |
用户登录时的相关配置 |
例如密码复杂度,登录方式 |
||
|
Sign-up |
用户注册时的相关配置 |
|||
|
Social and external providers |
通过第三方登录的配置,像是通过 Facebook, Google, Amazon or Apple..等其他供应商来授权 |
|||
|
Extensions |
通过一些自定义的验证行为,触发 AWS lambda function。此处是触发器的配置。 |
此处的触发条件是 cognito 规定好的。也即仅可以配置:要不要触发,触发哪一个function |
||
|
Security |
AWS WAF |
|||
|
Threat protection |
||||
|
Log streaming |
||||
|
Branding |
Domain |
|||
|
Managed login |
||||
|
Message templates |
||||
|
Identity Pool |
Overview |
|||
|
Authentication Providers |
||||
|
Roles |
||||
|
IAM Policies |
||||
|
Data Synchronization |
Cognito 主要是做 用户管理 的事情,它支持通过 密码、手机短信、邮箱地址、其他企业供应商(例如 facebook、apple account 等) 等方式授权 token,
本文主要描述 自定义校验 custom authentication 的方式,此处要求在 user pool 中配置 3 个 AWS lambda function ,cognito 将会触发它的执行。
Lambda function 也是 Amazon web service 其中之一,此处可以简单地把其当作一个AWS的 api 方法。
这里涉及到 3 个触发器:define auth challenge,create auth challenge,verify auth challenge
|
Custom authentication trigger type |
Define Auth Challenge |
custom authentication 的第一步,这里会返回 custom challenge name 到 cognito;同时也可以基于用户逻辑,直接在此处发布 token 。 |
|
Create Auth Challenge |
custom authentication 流程的第二步,实现自定义身份验证的步骤。通常在这一步中写入验证的答案,验证的问题可以是 captchas 或者其他安全问题 或 验证码 等。 |
|
|
Verify Auth Challenge |
custom authentication 的第三步,校验用户输入的答案与在 create auth challenge 中预设的答案是否一致 |
下文将描述我们的代码会如何与 cognito 交互,又是如何触发对应的 lambda function。
1.2. 流程图
登录步骤 1:输入账号

- 前端第一次调用接口,是提交登录的请求;
- 后端调用 AWSSDK.CognitoIdentifyProvider 中 cognitoClient.InitiateAuthAsync 方法,这个方法是 cognito 支持的自定义验证方式,它会自动触发到
define auth challenge,create auth challenge; - 此处发送短信的方式是后端去调用了一个 AWS Lambda Function
登录步骤 2:输入验证码

- 前端第二次调用的接口,是提交登录的验证码
- 后端会把验证码发送给 user pool 去做校验,通过了校验才能成功授权返回 token
* AWS Lambda Triggers
|
场景 |
SDK Function |
Trigger the Lambda |
|
sign-in 登录 |
InitiateAuthAsync |
Define Auth Challenge, Create Auth Challenge |
|
RespondToAuthChallengeAsync |
Verify Auth Challenge |
|
|
sign-up 注册 |
SignUpAsync |
Custom message trigger |
|
ConfirmSignUpAsync |
Define auth challenge
- 这个 trigger 用于决定下一个验证步骤,可以在这里配置走向密码验证或者自定义的验证方式。
- 基于正确的 user session 上,它进一步定义验证的流程
例如,用户通过密码验证之后,将进入到手机短信验证
// cognito 将会触发到配置在 user pool 上的 lambda trigger,event 是它的入参
exports.handler = async (event) => {
if (event.request.session.length === 1 && event.request.session[0].challengeName === 'SRP_A') {
// 是否直接发布 token
event.response.issueTokens = false;
// 是否验证失败
event.response.failAuthentication = false;
// 下一个验证方式的名字
event.response.challengeName = 'PASSWORD_VERIFIER';
} else if (event.request.session.length === 2 && event.request.session[1].challengeName === 'PASSWORD_VERIFIER' && event.request.session[1].challengeResult === true) {
event.response.issueTokens = false;
event.response.failAuthentication = false;
event.response.challengeName = 'CUSTOM_CHALLENGE';
} else if (event.request.session.length === 3 && event.request.session[2].challengeName === 'CUSTOM_CHALLENGE' && event.request.session[2].challengeResult === true) {
event.response.issueTokens = true;
event.response.failAuthentication = false;
} else {
event.response.issueTokens = false;
event.response.failAuthentication = true;
}
return event;
};
Create auth challenge
- 一旦
Define Auth Challenge触发器指明使用自定义验证,那么Create Auth Challenge就会被触发去生成验证的内容。 - 在这个步骤中所创建的校验内容,是用户必须要答复的。例如 发到 SMS、Email 上的验证码,或者 CAPTCHA 之类的验证问题。
例如在 Create Auth Challenge 上设定一个将发送到 Email 的验证码(one-time password,简称 OTP),
此时 Amazon Cognito 其实会存储这个 event 内容,关联到用户的 session 和 用于 Verify Auth Challenge 步骤作为校验的答案(这里是验证码)
lambda function 实现示例:
exports.handler = async (event) => {
if (event.request.challengeName === 'CUSTOM_CHALLENGE') {
const otp = '654321'; // Generate or set your OTP here
event.response.publicChallengeParameters = { otp: 'Enter the OTP sent to your email' };
event.response.privateChallengeParameters = { otp: otp };
event.response.challengeMetadata = 'CUSTOM_CHALLENGE';
}
return event;
};
Verify auth challenge
- 该触发器在用户提交验证码之后被触发
- 该触发器接收到用户输入的 验证码 后会与
Create Auth Challenge中的验证码相互匹配。如果校验正确,cognito 会处理返回的 event 并生成 token
lambda function 实现示例:
// TriggerSource is VerifyAuthChallengeResponse_Authentication
exports.handler = async (event) => {
const expectedOtp = event.request.privateChallengeParameters.otp;
const userResponse = event.request.challengeAnswer;
event.response.answerCorrect = userResponse === expectedOtp;
return event;
};
2. 集成到 .net 8 api
.NET 中需要使用 AWS SDK 提供的 API 来与 Cognito 进行交互,
引用包:AWSSDK.CognitoIdentityProvider ,下文代码使用的版本是 3.7.1.85
<PackageReference Include="AWSSDK.CognitoIdentityProvider" Version="3.7.1.85" />
添加引用
using Amazon.CognitoIdentityProvider;
using Amazon.CognitoIdentityProvider.Model;
cognitoClient 初始化:
var AWSregion = "ap-xxxxx-x";
_cognitoClient = new AmazonCognitoIdentityProviderClient(Amazon.RegionEndpoint.GetBySystemName(AWSregion));
2.1.1 注册 [signup]
public async Task<SignUpResponse> SignupAsync(SignUpDto user)
{
var userName = string.IsNullOrEmpty(user.Email) ? user.PhoneNumber : user.Email;
var request = new SignUpRequest
{
// 在 cognito user pool 中配置允许访问该 user pool 的 client 后,可以在cognito 上查看到这个 clientId
ClientId = _clientId,
// cognito 会校验代码复杂度,需要在 user pool 中配置;但此示例中密码是没有作用的
Password = "carcar@2024",
// 此处可以填手机号或邮箱地址; cognito user pool 中显示的 userName 是 user pool 用户管理意义上的 uuid
Username = userName
};
// 自定义的 user attribute
var nameAttribute = new AttributeType
{
Name = "name",
Value = user.Name
};
request.UserAttributes.Add(nameAttribute);
// 自定义的 user attribute
var emailAttribute = new AttributeType
{
Name = "email",
Value = user.Email
};
request.UserAttributes.Add(emailAttribute);
return await _cognitoClient.SignUpAsync(request);
}
可配置密码复杂度配置

可以配置对 user attribute 的必填要求

查看 user attribute

2.1.2 注册验证 [signup-confirm]
var confirmSignUpRequest = new ConfirmSignUpRequest
{
ClientId = "client id",
Username = "user phone / email",
ConfirmationCode = "verification code from sms or email"
};
var confirmSignUpResponse = await cognitoClient.ConfirmSignUpAsync(confirmSignUpRequest);
Console.WriteLine($"User {confirmSignUpResponse.UserConfirmed} confirmed successfully.")
2.1.3 重新发送验证码 [resend-confirmation]
// userName 可以是 cognito UserName,又或者是注册时写入的 userName 即邮箱或手机号
public async Task ResendConfirmationAsync(string userName)
{
var request = new ResendConfirmationCodeRequest
{
ClientId = _clientId,
Username = userName
};
var response = await _cognitoClient.ResendConfirmationCodeAsync(request);
}
2.2.1 登录 [signin]
var authRequest = new InitiateAuthRequest
{
ClientId = "the client id which configures in the user pool",
AuthFlow = AuthFlowType.CUSTOM_AUTH,
AuthParameters = new Dictionary<string, string>
{
{ "USERNAME", "your_username_or_phone_or_email" }
}
};
var authResponse = await cognitoClient.InitiateAuthAsync(authRequest);
2.2.2 登录验证 [signin-confirm]
校验验证码时,调用 RespondToAuthChallengeAsync
var respondToAuthChallengeRequest = new RespondToAuthChallengeRequest
{
ChallengeName = authResponse.ChallengeName,
ClientId = "your_client_id",
ChallengeResponses = new Dictionary<string, string>
{
{ "USERNAME", "your_username_or_phone_or_email" },
{ "SMS_MFA_CODE", "user_received_code" }
},
Session = authResponse.Session
};
var challengeResponse = await cognitoClient.RespondToAuthChallengeAsync(respondToAuthChallengeRequest);
var idToken = challengeResponse.AuthenticationResult.IdToken;
2.3 token 验证
在 Program 或 StartUp 的配置文件中,需要配置 Authentication 中间件
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = $"https://cognito-idp.{AWSregion}.amazonaws.com/{userPoolId}",
// ValidAudience = {userPoolId},
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
// Get JsonWebKeySet from AWS
var json = new WebClient().DownloadString($"https://cognito-idp.{AWSregion}.amazonaws.com/{userPoolId}/.well-known/jwks.json");
// Deserialize the result
var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
// Cast the result to be the type expected by IssuerSigningKeyResolver
return (IEnumerable<SecurityKey>)keys;
}
};
});
3. 为什么写这一篇文章
很多开发可能和我一样,没有成为一名云上工程师,或者说项目里并没有使用 Amazon Web Service,那么对于如何集成 AWS 可能是不感兴趣的。
那我为什么写这篇文章?
1、国内对 AWS 的应用较少,AWS 相关的资料大多是英文的,其实解读下来真的挺花时间。
2、现在新颖的技术层出不穷,我的希望是在探索 cognito 的过程中,建立一个快速理解的方法论。
这背后考验的是专业知识以及逻辑梳理能力。我们一定是:知其所以然,才能应对多变的表象。
当然,这里我指的是对云服务如何集成传统应用,或者说“我的应用要怎么上云”。
3、借此机会看一下云服务的设计,现在都怎么玩的。
理解云服务的应用不单止为我们多提供一种解决方案,在排查集成云集成中产生的问题,也会有所启发。
是否能够以小见大,找到表象的本质?
在既定的解决方案架构里面找到可以拓展的共性,能不能经验迁移?
无论如何,希望这篇文章对你有所收益。
References
[1] Amazon Cognito Identity Provider examples using AWS SDK for .NET
[2] Authentication flow examples with .NET for Amazon Cognito
[3] Authenticating users in ASP.NET Core MVC using Amazon Cognito
[4] Securing ASP.NET Core API with JWT Token using AWS Cognito
.net 8 C# 集成 AWS Cognito SMS/Email 注册与登录的更多相关文章
- 在aws ec2上使用root用户登录
aws ec2默认是使用ec2-user账号登陆的,对很多文件夹是没有权限的.如何使用root账号执行命令就是一个问题了.解决办法如下: 1.根据官网提供的方法登录连接到EC2服务器(官网推荐wind ...
- Open Phone, SMS, Email, Skype and Browser apps of Android in Unity3d
最近项目需要使用Android的一些基本功能,写插件各种悲剧,google了一下,如获至宝.Nice ! string url = String.Format("tel:{0}", ...
- SpringCloud微服务实战——搭建企业级开发框架(二十四):集成行为验证码和图片验证码实现登录功能
随着近几年技术的发展,人们对于系统安全性和用户体验的要求越来越高,大多数网站系统都逐渐采用行为验证码来代替图片验证码.GitEgg-Cloud集成了开源行为验证码组件和图片验证码,并在系统中添加可配置 ...
- 可选择Email和用户名登录的代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- aws linux主机root帐号登录
默认情况下,aws主机必须使用pem密码文件并且以ec2-user用户登录系统,之后很多操作都必须用sudo来以root权限执行操作,显得比较麻烦. 以下来自知乎的一个问答,亲测ok ## AWS E ...
- SpringBoot集成Spring Security(2)——自动登录
在上一章:SpringBoot集成Spring Security(1)——入门程序中,我们实现了入门程序,本篇为该程序加上自动登录的功能. 文章目录 一.修改login.html二.两种实现方式 2. ...
- 设置ecShop网店用户名和email均可登录
修改user.php文件,如果您网站的该文件修改过,按照下面的修改说明修改文件. 查找代码:elseif ($action == 'act_login') 在:$back_act = isset($_ ...
- Gitlab CI持续集成 - GitLab Runner 安装与注册
GitLab Runner安装 需要添加gitlab官方库: # For Debian/Ubuntu/Mint curl -L https://packages.gitlab.com/install/ ...
- java集成网站微信,微博,qq登录
微信 WechatConfig.java package com.meeno.chemical.common.sdk.wechat.config; import org.springframework ...
- 4、ABPZero系列教程之拼多多卖家工具 集成短信发送模块
ABPZero并没有手机短信发送功能,现在我们来集成一个,为后面注册.登录作铺垫. 阿里云短信服务 首先需要在阿里云开通短信服务,连接地址 开通后,在签名管理中添加一个签名 在模板管理中添加一个模板, ...
随机推荐
- 中电金信:云原生时代IT基础设施管理利器——基础设施即代码(IaC)
在数字化转型.零售业务快速发展.信创建设驱动下,应用架构.技术架构.基础架构都已向云原生快速演进,银行业IT基础设施管理产生了非常大的变化,当前银行业,正在开展新一轮的核心应用系统重构.基础平台统一 ...
- 离线yum安装k8s(直接yum安装k8s)快速部署
问题:如何在没有离线环境上服务器yum安装k8s环境? 环境:准备一台互联网的服务器+离线的服务器 写的比较简便........ 1.互联网服务操作添加阿里云YUM的软件源 cat > /etc ...
- Qt编写地图综合应用47-经纬度地址互相转换
一.前言 地址经纬度互换的功能只有在线地图有,因为需要去服务器查询对应的数据,拿到返回的数据,百度地图中需要用到BMap.Geocoder来实现这两个功能的互换,他内置了getPoint函数负责将地址 ...
- Qt通用方法及类库3
函数名 //设置全局样式 static void setStyle(QUIWidget::Style style); static void setStyle(const QString &q ...
- 特殊数据类型的深度分析:JSON、数组和 HSTORE 的实用价值
title: 特殊数据类型的深度分析:JSON.数组和 HSTORE 的实用价值 date: 2025/1/4 updated: 2025/1/4 author: cmdragon excerpt: ...
- IT系统架构的演化-copy
前言 一个成熟的大型网站(如淘宝.天猫.腾讯等)的系统架构并不是一开始设计时就具备完整的高性能.高可用.高伸缩等特性的,它是随着用户量的增加,业务功能的扩展逐渐演变完善的,在这个过程中,开发模式.技术 ...
- biancheng-Pygame(python)
http://c.biancheng.net/pygame/ Python Pygame 是一款专门为开发和设计 2D 电子游戏而生的软件包,它支 Windows.Linux.Mac OS 等操作系统 ...
- superset 相关视频(建议初学者开始刷2天视频,开眼界)
建议集中一段时间刷视频,不用具体知道怎么操作,先明白能干什么,大概在那里弄,达到什么效果,是否符合自己的预期,然后再根据具体遇到的问题,再找视频 另外,看的时候注意有版本的不同,具体操作时候,版本不同 ...
- 多方安全计算(6):MPC中场梳理
学习&转载文章:多方安全计算(6):MPC中场梳理 前言 诚为读者所知,数据出域的限制约束与数据流通的普遍需求共同催生了数据安全计算的需求,近一两年业界又统将能够做到多方数据可用不可见的技术归 ...
- # Vue3.5常用特性整理
Vue3.5 发布已近半年,抽空整理下常用的新增/改动特性 响应式 Props 解构 Vue3.5 中 Props 正式支持解构了,并添加了响应式跟踪 设置默认值 使用 JavaScript 原生的默 ...