晚上好!我正在构建 NextJS 15 + AWS Amplify 应用程序!我知道 AWS 尚未提供对 NextJS 15 的支持,但由于这是一个新应用程序,并且 AWS 很快就会提供对 NextJS 15 的支持,所以我决定开始研究它!
在此应用程序中,我正在处理专注于服务器操作的业务逻辑,到目前为止,我已经完成了与 Cognito 的整个自定义集成,用于用户创建、确认、密码恢复和登录。但是,关于最后一项,当我执行
signIn
包中的 aws-amplify
函数时,我收到一条响应,表明登录成功,如下所示。
页面.tsx
'use client'
import Link from "next/link";
import Image from "next/image";
import {useActionState} from "react";
import {signInFormType} from "./schema";
import {Brand} from "@/components/ui/brand";
import {Label} from "@/components/ui/label";
import {Submit} from "@/components/ui/submit";
import {Button} from "@/components/ui/button";
import {Heading} from "@/components/ui/heading";
import {Divider} from "@/components/ui/divider";
import {signInWithRedirect} from "aws-amplify/auth";
import {Input, InputError} from "@/components/ui/input";
import {signInWithCredentialsAction} from "./controller";
import {Alert, AlertDescription} from "@/components/ui/alert";
export default function Page() {
const [state, formAction] = useActionState(signInWithCredentialsAction, {} as signInFormType);
return (
<>
<Brand className="text-5xl"/>
<Heading title="Sign In" description="Enter your credentials in the fields below to access your dashboard."/>
{state?.message && (<Alert variant={state?.success ? 'default' : 'destructive'}><AlertDescription>{state?.message}</AlertDescription></Alert>)}
<form action={formAction} className="space-y-4">
<div>
<Label>Email Address</Label>
<Input type="text" name="email" defaultValue={state?.data?.email || undefined} placeholder="[email protected]"/>
<InputError message={state?.errors?.fieldErrors?.email} />
</div>
<div>
<div className="flex-between">
<Label>Password</Label>
<Link href="/forgot-password" className="link text-sm pr-1">Forgot your password?</Link>
</div>
<Input type="password" name="password" placeholder="your password"/>
<InputError message={state?.errors?.fieldErrors?.password} />
</div>
<div className="pt-4">
<Submit behavior="full">Sign In</Submit>
</div>
</form>
<div className="text-center text-muted-foreground text-sm">
Don't have an account? <Link href="/register" className="link !font-bold">Sign Up</Link>
</div>
<Divider text="ou"/>
<Button variant="outline" behavior="full" size="sm" onClick={async () => await signInWithRedirect({provider: 'Google'})}>
<Image src="/google.svg" width={24} height={24} alt="Google" className="size-4"/>
<span className="normal-case font-bold">sign in with Google</span>
</Button>
<div className="flex flex-col items-center justify-center">
<Link href="/" className="link clicked">Home Page</Link>
</div>
</>
)
}
在服务器操作方面,我有以下代码。
控制器.tsx
'use server'
import {signIn, signInWithRedirect} from "aws-amplify/auth";
import {redirect} from "next/navigation";
import {signInSchema, signInSchemaErrorType, signInSchemaType} from "./schema";
export async function signInWithCredentialsAction(prevState: unknown, payload: FormData) {
const validated = signInSchema.safeParse(Object.fromEntries(payload.entries()));
if (!validated.success) {
return {
errors: validated.error.formErrors as signInSchemaErrorType,
data: Object.fromEntries(payload.entries()) as signInSchemaType
}
}
const {nextStep} = await signIn({
username: validated.data.email,
password: validated.data.password
});
if (isSignedIn) {
return redirect(`/dashboard`);
}
return {
success: false,
message: 'Login could not be completed.',
data: Object.fromEntries(payload.entries()) as signInSchemaType
};
}
这是我调用
signIn
方法时得到的响应:
isSignedIn: true
nextStep: { signInStep: 'DONE' }
我还编写了一些辅助函数来协助检索经过身份验证的用户和用户的会话。
/lib/amplify.ts
import {cookies} from "next/headers";
import {ResourcesConfig} from "aws-amplify";
import outputs from "@/amplify_outputs.json";
import {type Schema} from "@/amplify/data/resource";
import {createServerRunner} from "@aws-amplify/adapter-nextjs";
import {getCurrentUser, fetchAuthSession} from "aws-amplify/auth/server";
import {generateServerClientUsingCookies} from "@aws-amplify/adapter-nextjs/data";
export const {runWithAmplifyServerContext} = createServerRunner({config: outputs as ResourcesConfig});
export const cookieBasedClient = generateServerClientUsingCookies<Schema>({config: outputs as ResourcesConfig, cookies, authMode: "iam"});
export const isAuthenticated = async (): Promise<boolean> => {
return await runWithAmplifyServerContext({
nextServerContext: {cookies},
async operation(contextSpec) {
try {
const user = await getCurrentUser(contextSpec);
return !!user;
} catch {
return false;
}
},
});
};
但由于某种我不明白的原因,当我调用该方法时
isAuthenticated()
我总是得到一个false
作为回报。
当我学习 NextJs 和 AWS Amplify 几周时,我有点迷失了!如果有人可以帮助我解决这个问题,只是为了在 AWS 不发布 Next15 支持的情况下制定一些解决方法,我将非常感激。
有同样的问题:放大在客户端不正确,因此后续的服务器调用有一个初始令牌:必须像这样调整
<ConfigureAmplifyClientSide />
:
'use client';
import '@aws-amplify/ui-react/styles.css';
import { Amplify, type ResourcesConfig } from 'aws-amplify';
import outputs from '../../amplify_outputs.json';
export const authConfig: ResourcesConfig['Auth'] = {
Cognito: {
userPoolId: String(process.env.NEXT_PUBLIC_USER_POOL_ID),
userPoolClientId: String(
process.env.NEXT_PUBLIC_USER_POOL_CLIENT_ID
),
},
};
Amplify.configure(
{
...outputs,
Auth: authConfig,
},
{
ssr: true,
}
);
export default function ConfigureAmplifyClientSide() {
return null;
}