Next.js Cognito 身份验证 API 在本地工作,但在使用 AWS CDK 部署到 AWS 时不起作用

问题描述 投票:0回答:1

我目前正在构建一个 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 中配置了环境变量。非常感谢您的帮助!

next.js sdk amazon-cognito aws-cdk next-auth
1个回答
0
投票

这只是一个猜测,但前段时间我尝试使用 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:
              - "*"
© www.soinside.com 2019 - 2024. All rights reserved.