客观的:
- 使用 Cognito 进行身份验证(使用下面的 serverless.yml 配置)
- 点击经过身份验证的端点 GET /users 以触发 lambda 作业。
- 基于IAM策略,限制基于cognito用户查询的DynamoDB表的访问
cognito-identity.amazonaws.com:sub
使用LeadingKey条件。
问题:我的策略似乎没有填充认知变量${cognito-identity.amazonaws.com:sub}
。如果我手动指定dynamodb:LeadingKeys
有了一个值,它就可以正常工作。所以看来我只需要 Cognito 正确填充子值,我已经到处寻找但找不到解决方案。
我的 lambda 角色/策略(将生成的无服务器版本修改为具有包含 Cognito 和 DynamoDB 规则的信任策略):
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"logs:CreateLogStream",
"logs:CreateLogGroup"
],
"Resource": [
"arn:aws:logs:us-east-1:xxx:log-group:/aws/lambda/exeampleservice*:*"
],
"Effect": "Allow"
},
{
"Action": [
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:us-east-1:xxxx:log-group:/aws/lambda/exampleservice*:*:*"
],
"Effect": "Allow"
},
{
"Effect": "Allow",
"Action": [
"dynamodb:PutItem",
"dynamodb:GetItem",
"dynamodb:Query"
],
"Resource": "*",
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": "${cognito-identity.amazonaws.com:sub}"
}
}
}
]
}
具有信任关系:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
},
{
"Effect": "Allow",
"Principal": {
"Federated": "cognito-identity.amazonaws.com"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"cognito-identity.amazonaws.com:aud": "us-east-1:<identity pool id>"
}
}
}
]
}
附加设置信息:
- 使用带有http协议的API网关。
- 在下面的 serverless.yml 中创建了 userPool。
- 设置 Cognito 身份池(联合)。
- 创建了一个 userPool 组并为其分配了我的身份池 ID。
- 将池中的用户分配给组。
- 使用 Cognito 和 id 进行身份验证,访问令牌显示身份 id 令牌:
{
"sub": "xxxx",
"cognito:groups": [
"TestGroup"
],
"email_verified": true,
"iss": "https://cognito-idp.us-east-1.amazonaws.com/<poolid>",
"cognito:username": "xxx",
"cognito:roles": [
"arn:aws:iam::xxxx:role/Cognito_IdentityPoolAuth_Role"
],
"aud": "xxx",
"event_id": "xxx",
"token_use": "id",
"auth_time": 1595367712,
"exp": 1595371310,
"iat": 1595367710,
"email": "[email protected]"
}
org: exampleorg
app: exampleapp
service: exampleservers
provider:
name: aws
stage: dev
runtime: nodejs12.x
iamManagedPolicies:
- 'arn:aws:iam::xxxx:policy/UserAccess'
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- { 'Fn::ImportValue': '${self:provider.stage}-UsersTableArn' }
Condition:
{
'ForAllValues:StringEquals':
{ // use join to avoid conflict with serverless variable syntax. Ouputs
'dynamodb:LeadingKeys':
[Fn::Join: ['', ['$', '{cognito-identity.amazonaws.com:sub}']]],
},
}
httpApi:
authorizers:
serviceAuthorizer:
identitySource: $request.header.Authorization
issuerUrl:
Fn::Join:
- ''
- - 'https://cognito-idp.'
- '${opt:region, self:provider.region}'
- '.amazonaws.com/'
- Ref: serviceUserPool
audience:
- Ref: serviceUserPoolClient
functions:
# auth
login:
handler: auth/handler.login
events:
- httpApi:
method: POST
path: /auth/login
# authorizer: serviceAuthorizer
# user
getProfileInfo:
handler: user/handler.get
events:
- httpApi:
method: GET
path: /user/profile
authorizer: serviceAuthorizer
resources:
Resources:
HttpApi:
DependsOn: serviceUserPool
serviceUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: service-user-pool-${opt:stage, self:provider.stage}
UsernameAttributes:
- email
AutoVerifiedAttributes:
- email
serviceUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: service-user-pool-client-${opt:stage, self:provider.stage}
AllowedOAuthFlows:
- implicit
AllowedOAuthFlowsUserPoolClient: true
AllowedOAuthScopes:
- phone
- email
- openid
- profile
- aws.cognito.signin.user.admin
UserPoolId:
Ref: serviceUserPool
CallbackURLs:
- https://localhost:3000
ExplicitAuthFlows:
- ALLOW_USER_SRP_AUTH
- ALLOW_REFRESH_TOKEN_AUTH
GenerateSecret: false
SupportedIdentityProviders:
- COGNITO
serviceUserPoolDomain:
Type: AWS::Cognito::UserPoolDomain
Properties:
UserPoolId:
Ref: serviceUserPool
Domain: service-user-pool-domain-${opt:stage, self:provider.stage}-${self:provider.environment.DOMAIN_SUFFIX}
我已经尝试了几乎所有方法来获取变量${cognito-identity.amazonaws.com:sub}
在政策中,但似乎没有任何作用。
有谁知道如何解决这个问题?或者我可能会错过什么。 (如果我错过了任何重要的内容,我将更新更多信息)。
Thanks!
编辑:(附加信息)
我的登录函数(lambda + HTTP API)如下,我通过用户/密码授权User,然后调用CognitoIdentityCredentials“注册”我的身份并从池中获取我的identityId。 (我验证我正在注册,因为身份池显示用户)
然后,我的登录调用会使用 accessToken、idToken、identityId 进行响应。
我的所有其他 API 调用都在对我进行授权的承载授权调用中使用 idToken,但似乎并未假定我的身份池的授权角色,而是使用我的 lambda 角色来执行。
我在这里缺少什么?我认为 Cognito 会处理身份验证池的假设角色,但看起来整个?任何帮助表示赞赏!
我的请求上下文(来自我的登录函数,请注意身份对象充满空值):
requestContext: {
accountId: 'xxx',
apiId: 'xxx',
domainName: 'xxxx.execute-api.us-east-1.amazonaws.com',
domainPrefix: 'xxx',
extendedRequestId: 'xxxx=',
httpMethod: 'POST',
identity: {
accessKey: null,
accountId: null,
caller: null,
cognitoAuthenticationProvider: null,
cognitoAuthenticationType: null,
cognitoIdentityId: null,
cognitoIdentityPoolId: null,
principalOrgId: null,
sourceIp: 'xxxx',
user: null,
userAgent: 'PostmanRuntime/7.26.1',
userArn: null
},
我的登录功能
const AWS = require('aws-sdk');
const AmazonCognitoIdentity = require('amazon-cognito-identity-js');
global.fetch = require('node-fetch').default; // .default for webpack.
const USER_POOL_ID = process.env.USER_POOL_ID;
const USER_POOL_CLIENT_ID = process.env.USER_POOL_CLIENT_ID;
const USER_POOL_IDENTITY_ID = process.env.USER_POOL_IDENTITY_ID;
console.log('USER_POOL_ID', USER_POOL_ID);
console.log('USER_POOL_CLIENT_ID', USER_POOL_CLIENT_ID);
console.log('USER_POOL_CLIENT_ID', USER_POOL_IDENTITY_ID);
const poolData = {
UserPoolId: USER_POOL_ID,
ClientId: USER_POOL_CLIENT_ID,
};
const poolRegion = 'us-east-1';
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData);
function login(Username, Password) {
var authenticationDetails = new AmazonCognitoIdentity.AuthenticationDetails({
Username,
Password,
});
var userData = {
Username,
Pool: userPool,
};
var cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData);
return new Promise((resolve, reject) => {
cognitoUser.authenticateUser(authenticationDetails, {
onSuccess: function (result) {
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: USER_POOL_IDENTITY_ID, // your identity pool id here
Logins: {
// Change the key below according to the specific region your user pool is in.
[`cognito-idp.${poolRegion}.amazonaws.com/${USER_POOL_ID}`]: result
.getIdToken()
.getJwtToken(),
},
});
//refreshes credentials using AWS.CognitoIdentity.getCredentialsForIdentity()
AWS.config.credentials.refresh((error) => {
if (error) {
console.error(error);
} else {
// Instantiate aws sdk service objects now that the credentials have been updated.
// example: var s3 = new AWS.S3();
console.log('Successfully Refreshed!');
AWS.config.credentials.get(() => {
// return back all tokens and identityId in login call response body.
const identityId = AWS.config.credentials.identityId;
const tokens = {
accessToken: result.getAccessToken().getJwtToken(),
idToken: result.getIdToken().getJwtToken(),
refreshToken: result.getRefreshToken().getToken(),
identityId,
};
resolve(tokens);
});
}
});
},
onFailure: (err) => {
console.log(err);
reject(err);
},
});
});
}
module.exports = {
login,
};