使用 Cognito & API Gateway & Lambda (Python) 的无密码身份验证流程
Passwordless authentication flow using Cognito & API Gateway & Lambda (Python)
我一直在尝试使用 AWS Cognito & API 网关 & Lambda (Python)
实施无密码身份验证
我关注了这些文章:
https://medium.com/digicred/password-less-authentication-in-cognito-cafa016d4db7
https://medium.com/@pjatocheseminario/passwordless-api-using-cognito-and-serverless-framework-7fa952191352
我已经配置了 Cognito(接受 CUSTOM_AUTH),添加了 Lambda,并创建了 API 端点:
/sign-up
/initiate-auth (aka initiate login)
/respond-to-auth-challenge (aka (verify login)
调用 initiateAuth 时,我收到以下响应:
调用 InitiateAuth 操作时发生错误(NotAuthorizedException):用户名或密码不正确。"
我正在使用不需要密码的 CUSTOM_AUTH,并且用户名绝对正确,因为它实际上启动了身份验证流程并且我收到了代码,但是因为 boto3 没有响应session 我无法继续认证。
这就是我对 Cognito 的称呼:
res = cognito.initiate_auth(
ClientId=client_id,
AuthFlow="CUSTOM_AUTH",
AuthParameters={
"USERNAME": email,
"PASSWORD": random_password
}
)
这可能是我遗漏的一些小东西,但我不知道是什么。
我遇到了同样的错误,我认为该错误消息具有误导性。
当您在 Create-Auth-Challenge lambda 中没有正确响应时,您将收到此错误。因此,请确保您的 lambda 中的一切都是正确的。
你的客户端代码看起来没问题,我的有 ClientId
参数,但如果你的代码没有引发异常,那么它应该没问题。除非您在创建应用程序客户端时选中了 Generate client secret
选项。
如果是这种情况,那么您必须像下面这样在 AuthParameters
中传递 SECRET_HASH
:
import hmac
import hashlib
import base64
def get_secret_hash(email, client_id, client_secret):
"""
A keyed-hash message authentication code (HMAC) calculated using
the secret key of a user pool client and username plus the client
ID in the message.
"""
message = email + client_id
client_secret = str.encode(client_secret)
dig = hmac.new(client_secret, msg=message.encode('UTF-8'), digestmod=hashlib.sha256).digest()
return base64.b64encode(dig).decode()
client.admin_initiate_auth(
UserPoolId=COGNITO_USER_POOL_ID,
ClientId=CLIENT_ID,
AuthFlow='CUSTOM_AUTH',
AuthParameters={
'USERNAME': email,
'SECRET_HASH': get_secret_hash(email, CLIENT_ID, CLIENT_SECRET) # Omit if secret key option is disabled.
},
)
接下来,仔细检查以下内容:
在 App clients > * > Auth Flows Configuration
下,是否为您的客户端启用了 ALLOW_CUSTOM_AUTH
选项?
在App integration > App client settings > * > Enabled Identity Providers
下,是否选择了您的用户池?
如果您已正确设置 Cognito,但您的代码仍然无法运行,则可能是 lambda 代码。您可能知道这一点,但对于无密码自定义身份验证,您需要使用 3 个 lambda 触发器:Define Auth Challenge
、Create Auth Challenge
和 Verify Auth Challenge
.
自定义 auth lambdas 事件按以下顺序触发:
- DefineAuthChallenge_Authentication:
- 从技术上讲,这里可以将 issueTokens 设置为 True 以 return 个令牌,而无需执行其余步骤。
def lambda_handler(event, context):
if event['triggerSource'] == 'DefineAuthChallenge_Authentication':
event['response']['challengeName'] = 'CUSTOM_CHALLENGE'
event['response']['issueTokens'] = False
event['response']['failAuthentication'] = False
if event['request']['session']: # Needed for step 4.
# If all of the challenges are answered, issue tokens.
event['response']['issueTokens'] = all(
answered_challenge['challengeResult'] for answered_challenge in event['request']['session'])
return event
- CreateAuthChallenge_Authentication:
def lambda_handler(event, context):
if event['triggerSource'] == 'CreateAuthChallenge_Authentication':
if event['request']['challengeName'] == 'CUSTOM_CHALLENGE':
event['response']['privateChallengeParameters'] = {}
event['response']['privateChallengeParameters']['answer'] = 'YOUR CHALLENGE ANSWER HERE'
event['response']['challengeMetadata'] = 'AUTHENTICATE_AS_CHALLENGE'
return event
那么您的客户必须回应挑战:
client.respond_to_auth_challenge(
ClientId=CLIENT_ID,
ChallengeName='CUSTOM_CHALLENGE',
Session=session,
ChallengeResponses={
'USERNAME': email,
'ANSWER': 'Extra Protection!',
'SECRET_HASH': get_secret_hash(email, CLIENT_ID, CLIENT_SECRET) # Omit if secret key option is disabled.
}
)
- VerifyAuthChallengeResponse_Authentication:
def lambda_handler(event, context):
if event['triggerSource'] == 'VerifyAuthChallengeResponse_Authentication':
if event['request']['challengeAnswer'] == event['request']['privateChallengeParameters']['answer']:
event['response']['answerCorrect'] = True
return event
- DefineAuthChallenge_Authentication:
- 设置
event['response']['issueTokens']
到 True
到 return 个令牌(步骤 1 中显示的代码),或发出另一个挑战以继续重复步骤 1-3。
最后,确保您的用户池也启用了不区分大小写选项。另外,如果用户处于 FORCE_CHANGE_PASSWORD
状态,我不记得 CUSTOM_AUTH
流程是否有效。如果用户处于该状态,则尝试使用 sdk 设置永久密码以将状态设置为 CONFIRMED
.
我一直在尝试使用 AWS Cognito & API 网关 & Lambda (Python)
实施无密码身份验证我关注了这些文章: https://medium.com/digicred/password-less-authentication-in-cognito-cafa016d4db7 https://medium.com/@pjatocheseminario/passwordless-api-using-cognito-and-serverless-framework-7fa952191352
我已经配置了 Cognito(接受 CUSTOM_AUTH),添加了 Lambda,并创建了 API 端点:
/sign-up
/initiate-auth (aka initiate login)
/respond-to-auth-challenge (aka (verify login)
调用 initiateAuth 时,我收到以下响应: 调用 InitiateAuth 操作时发生错误(NotAuthorizedException):用户名或密码不正确。"
我正在使用不需要密码的 CUSTOM_AUTH,并且用户名绝对正确,因为它实际上启动了身份验证流程并且我收到了代码,但是因为 boto3 没有响应session 我无法继续认证。
这就是我对 Cognito 的称呼:
res = cognito.initiate_auth(
ClientId=client_id,
AuthFlow="CUSTOM_AUTH",
AuthParameters={
"USERNAME": email,
"PASSWORD": random_password
}
)
这可能是我遗漏的一些小东西,但我不知道是什么。
我遇到了同样的错误,我认为该错误消息具有误导性。 当您在 Create-Auth-Challenge lambda 中没有正确响应时,您将收到此错误。因此,请确保您的 lambda 中的一切都是正确的。
你的客户端代码看起来没问题,我的有 ClientId
参数,但如果你的代码没有引发异常,那么它应该没问题。除非您在创建应用程序客户端时选中了 Generate client secret
选项。
如果是这种情况,那么您必须像下面这样在 AuthParameters
中传递 SECRET_HASH
:
import hmac
import hashlib
import base64
def get_secret_hash(email, client_id, client_secret):
"""
A keyed-hash message authentication code (HMAC) calculated using
the secret key of a user pool client and username plus the client
ID in the message.
"""
message = email + client_id
client_secret = str.encode(client_secret)
dig = hmac.new(client_secret, msg=message.encode('UTF-8'), digestmod=hashlib.sha256).digest()
return base64.b64encode(dig).decode()
client.admin_initiate_auth(
UserPoolId=COGNITO_USER_POOL_ID,
ClientId=CLIENT_ID,
AuthFlow='CUSTOM_AUTH',
AuthParameters={
'USERNAME': email,
'SECRET_HASH': get_secret_hash(email, CLIENT_ID, CLIENT_SECRET) # Omit if secret key option is disabled.
},
)
接下来,仔细检查以下内容:
在 App clients > * > Auth Flows Configuration
下,是否为您的客户端启用了 ALLOW_CUSTOM_AUTH
选项?
在App integration > App client settings > * > Enabled Identity Providers
下,是否选择了您的用户池?
如果您已正确设置 Cognito,但您的代码仍然无法运行,则可能是 lambda 代码。您可能知道这一点,但对于无密码自定义身份验证,您需要使用 3 个 lambda 触发器:Define Auth Challenge
、Create Auth Challenge
和 Verify Auth Challenge
.
自定义 auth lambdas 事件按以下顺序触发:
- DefineAuthChallenge_Authentication:
- 从技术上讲,这里可以将 issueTokens 设置为 True 以 return 个令牌,而无需执行其余步骤。
def lambda_handler(event, context):
if event['triggerSource'] == 'DefineAuthChallenge_Authentication':
event['response']['challengeName'] = 'CUSTOM_CHALLENGE'
event['response']['issueTokens'] = False
event['response']['failAuthentication'] = False
if event['request']['session']: # Needed for step 4.
# If all of the challenges are answered, issue tokens.
event['response']['issueTokens'] = all(
answered_challenge['challengeResult'] for answered_challenge in event['request']['session'])
return event
- CreateAuthChallenge_Authentication:
def lambda_handler(event, context):
if event['triggerSource'] == 'CreateAuthChallenge_Authentication':
if event['request']['challengeName'] == 'CUSTOM_CHALLENGE':
event['response']['privateChallengeParameters'] = {}
event['response']['privateChallengeParameters']['answer'] = 'YOUR CHALLENGE ANSWER HERE'
event['response']['challengeMetadata'] = 'AUTHENTICATE_AS_CHALLENGE'
return event
那么您的客户必须回应挑战:
client.respond_to_auth_challenge(
ClientId=CLIENT_ID,
ChallengeName='CUSTOM_CHALLENGE',
Session=session,
ChallengeResponses={
'USERNAME': email,
'ANSWER': 'Extra Protection!',
'SECRET_HASH': get_secret_hash(email, CLIENT_ID, CLIENT_SECRET) # Omit if secret key option is disabled.
}
)
- VerifyAuthChallengeResponse_Authentication:
def lambda_handler(event, context):
if event['triggerSource'] == 'VerifyAuthChallengeResponse_Authentication':
if event['request']['challengeAnswer'] == event['request']['privateChallengeParameters']['answer']:
event['response']['answerCorrect'] = True
return event
- DefineAuthChallenge_Authentication:
- 设置
event['response']['issueTokens']
到True
到 return 个令牌(步骤 1 中显示的代码),或发出另一个挑战以继续重复步骤 1-3。
- 设置
最后,确保您的用户池也启用了不区分大小写选项。另外,如果用户处于 FORCE_CHANGE_PASSWORD
状态,我不记得 CUSTOM_AUTH
流程是否有效。如果用户处于该状态,则尝试使用 sdk 设置永久密码以将状态设置为 CONFIRMED
.