我目前正在构建一个 Next.js 应用程序(应用程序路由器),我使用 cdk-nextjs-standalone 构造通过 AWS CDK 部署该应用程序。这是我的 CDK 堆栈:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { Nextjs } from 'cdk-nextjs-standalone';
export class PresentoloB2BStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const nextjs = new Nextjs(this, 'Nextjs', {
nextjsPath: '../',
environment: {
COGNITO_CLIENT_ID: process.env.COGNITO_CLIENT_ID || '',
AUTH_SECRET: process.env.AUTH_SECRET || ''
}
});
const userPool = new cdk.aws_cognito.UserPool(this, 'myuserpool', {
userPoolName: 'PresentoloB2B-userpool',
signInCaseSensitive: false, // case insensitive is preferred in most situations
selfSignUpEnabled: false,
autoVerify: { email: true },
userInvitation: {
emailSubject: 'We have set up a new account for you',
emailBody: 'Hello {username}, thank you for choosing us! We have set up a new account for you. Your temporary password is {####}',
},
signInAliases: {
username: true,
email: true,
},
passwordPolicy: {
minLength: 8,
requireLowercase: true,
requireUppercase: true,
requireDigits: true,
requireSymbols: true,
},
accountRecovery: cdk.aws_cognito.AccountRecovery.EMAIL_ONLY,
});
// Add UserPoolClient
const userPoolClient = userPool.addClient('userpoolclient', {
userPoolClientName: 'PresentoloB2B-client',
authFlows: {
userPassword: true,
custom: true,
userSrp: true,
},
supportedIdentityProviders: [
cdk.aws_cognito.UserPoolClientIdentityProvider.COGNITO,
],
preventUserExistenceErrors: true,
accessTokenValidity: cdk.Duration.days(1),
idTokenValidity: cdk.Duration.days(1),
refreshTokenValidity: cdk.Duration.days(30),
enableTokenRevocation: true,
});
new cdk.CfnOutput(this, "CloudFrontDistributionDomain", {
value: nextjs.distribution.distributionDomain,
});
new cdk.CfnOutput(this, "UserPoolId", {
value: userPool.userPoolId,
});
new cdk.CfnOutput(this, "UserPoolClientId", {
value: userPoolClient.userPoolClientId,
});
}
}
现在我遇到了以下无法解决的问题:正如您在我的 cdk 堆栈中看到的,我的应用程序使用 AWS Cognito 进行身份验证。因此,我有这个 auth.js 文件:
import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"
import AWS from 'aws-sdk'
import process from 'process'
export const { handlers, signIn, signOut, auth } = NextAuth({
providers: [
Credentials({
// You can specify which fields should be submitted, by adding keys to the `credentials` object.
// e.g. domain, username, password, 2FA token, etc.
name: "Credentials",
credentials: {
username: { label: "Username", type: "text", placeholder: "Username" },
password: { label: "Password", type: "password" }
},
authorize: async (credentials) => {
const cognito = new AWS.CognitoIdentityServiceProvider();
if (!credentials) return null;
const params = {
AuthFlow: 'USER_PASSWORD_AUTH',
ClientId: process.env.COGNITO_CLIENT_ID,
AuthParameters: {
USERNAME: credentials.username,
PASSWORD: credentials.password, // Use raw password
},
};
try {
const response = await cognito.initiateAuth(params).promise();
console.log('Cognito response:', response); // Log the response
const user = {
id: response.AuthenticationResult?.AccessToken,
name: credentials.username,
};
return user;
} catch (error) {
console.error('Detailed Cognito error:', JSON.stringify(error, null, 2));
if (error.code === 'NotAuthorizedException') {
// Invalid username or password
throw new Error('Invalid username or password');
}
throw error; // Rethrow other errors
}
},
}),
],
})
此 auth.js 文件在
src/app/api/auth/[...nextauth]/route.js
下用作 API:
import { handlers } from "../../../../../auth"
export const { GET, POST } = handlers
此 API 的使用方式如下:
import { signIn } from 'next-auth/react';
// some code
const handleSubmit = async (e) => {
e.preventDefault();
try {
await setLoading(true);
const result = await signIn('credentials', {
redirect: false,
username,
password,
});
await setLoading(false);
if (result.error) {
setError(true);
} else {
// Redirect to dashboard or home page
window.location.href = '/u/generate';
}
} catch (error) {
setError(translations.login_error);
}
}
//some other code
这里有一个奇怪的事情:由于某种原因,这个登录功能只能在本地使用(使用
npm run dev
)。一旦我尝试在部署的(可通过 AWS CloudFront URL 访问)版本中使用此登录功能,我就会被重定向到 https://XXXXXXXX.cloudfront.net/api/auth/ 下的 500 内部服务器错误页面错误。我已在 .env 和 .env.local 中配置了环境变量。非常感谢您的帮助!
这只是一个猜测,但前段时间我尝试使用 Cognito 身份验证部署 Nuxt (Vue) 静态网站(托管在 S3 和 CloudFront 上)并遇到了类似的问题。一切都在本地运行,但一旦部署,身份验证过程就会失败。打开开发者控制台,看看你的请求是否没有被CORS阻止。
我必须明确地将 Cognito 添加到 S3 存储桶的 CORS 策略中。
Resources:
WebsiteBucket:
Type: AWS::S3::Bucket
Properties:
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
CorsConfiguration:
CorsRules:
- AllowedMethods:
- POST
AllowedOrigins:
- cognito-idp.eu-west-1.amazonaws.com
AllowedHeaders:
- "*"