NEXTAUTH_URL 不起作用时如何定义自定义基本路径?
How to define a custom base path when NEXTAUTH_URL doesn't work?
上下文
我正在使用 NextJS v12.0.7
、React v17.0.2
、NextAuth v4.1.0
和 Typescript v4.3.5
。
我想基于 NextAuth documentation 创建一个简单的身份验证系统,并在登录后重定向到主页,所以我在 pages/api/auth
文件夹中创建了一个名为 [...nextauth].ts
的文件包含以下代码部分:
export default NextAuth({
providers: [
CredentialsProvider({
id: "credentials",
name: "Login",
credentials: {
username: { type: "email" },
password: { type: "password" },
},
async authorize(credentials) {
// [...]
},
}),
],
// [...]
callbacks: {
// [...]
redirect({ url, baseUrl }) {
console.log("redirect - url ", url, "baseUrl ", baseUrl); // This is what I was checking
if(url.startsWith(baseUrl)) {
return url
} else if(url.startsWith("/")) {
return new URL(url, baseUrl).toString();
}
return baseUrl;
}
},
})
对于我的 NextJS 项目,我使用了 next.config.js
文件中定义的基本路径 /espace-personnel
,所以我在 .env.local
文件中定义了 NEXTAUTH_URL
NEXTAUTH_URL
37=]:
NEXTAUTH_URL=http://localhost/espace-personnel/api/auth
我的问题
我在重定向回调中检查 url
和 baseUrl
变量的地方,我可以看到我的 NEXTAUTH_URL
变量定义不正确,或者我误解了一些东西。
这是 console.log("redirect - url ", url, "baseUrl ", baseUrl);
的结果:
redirect - url http://localhost:3000 baseUrl http://localhost
我已经做过研究,但在 Google 或 Whosebug 上找不到像我这样的案例,我是 NextAuth 的新手,所以我可能误解了一些东西。有人知道我做错了什么吗?
编辑 (15/01/2022)
再三考虑后,我决定直接使用 process.env.NEXTAUTH_URL 检查我的 env 变量,所以我在之前的 console.log()
:
之后添加了该行
console.log("NEXTAUTH_URL", process.env.NEXTAUTH_URL)
结果如下:
NEXTAUTH_URL http://localhost/espace-personnel/api/auth
所以,事实上,这不是定义 NEXTAUTH_URL 的问题,我想我对 NextAuth 的工作方式有一些误解,我会继续尝试找到解决我的问题的方法并在那里分享我在找东西。
编辑 (16/01/2022)
经过一些研究,我发现我们可以使用 signIn 方法传递 callbackUrl,所以我在 [...nextauth].ts
中定义了我的页面:
pages: {
signIn: process.env.NEXT_PUBLIC_BASE_URL + '/connexion',
signOut: process.env.NEXT_PUBLIC_BASE_URL + '/deconnexion',
error: process.env.NEXT_PUBLIC_BASE_URL + '/connexion/erreur', // Error code passed in query string as ?error=
},
这是我的登录表单代码:
import React, { useState } from "react";
import Alert from "../../ui/Alert/Alert";
import Button from "../../ui/Button/Button";
import Card from "../../ui/Card/Card";
import Divider from "../../ui/Divider/Divider";
import { getCsrfToken, signIn } from "next-auth/react";
import Input from "../../ui/Input/Input";
import styles from "./LoginForm.module.scss";
import Router from 'next/router';
type TAlertTitle = string;
type TAlertMessage = string;
type TAlertType = "info" | "warning" | "success" | "error";
export default function LoginForm({ csrfToken }: { csrfToken: string }) {
const [alertTitle, setAlertTitle] = useState<TAlertTitle>("Information");
const [alertMessage, setAlertMessage] = useState<TAlertMessage>("Juste un exemple");
const [alertType, setAlertType] = useState<TAlertType>("info");
async function onSubmit(event: React.SyntheticEvent<HTMLFormElement>) {
const target = event.target as typeof event.target & {
username: { value: string },
password: { value: string },
};
// Login attempt
const result = signIn('credentials', {
callbackUrl: process.env.NEXT_PUBLIC_BASE_URL,
username: target.username.value,
password: target.password.value
});
console.log(result);
event.preventDefault();
}
return (
<Card className={styles.card}>
<p className={'textSize40 fontWeightExtraBold textAlignCenter'}>
Connexion à votre espace personnel
</p>
<Divider className={styles.divider} />
<form onSubmit={onSubmit}>
<Alert title={alertTitle} message={alertMessage} type={alertType}></Alert>
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
<Input id="username" name="username" className="width100" type="email" autoComplete="email" placeholder="Adresse mail" leftIconLib="line-awesome" leftIcon="envelope" required />
<Input id="password" name="password" className="width100" type="password" autoComplete="current-password" placeholder="Mot de passe" leftIconLib="line-awesome" leftIcon="key" required />
<Button className="width100" theme="accent" type="submit">Se connecter</Button>
<Button className="width100" type="submit">Identifiants oubliés</Button>
</form>
</Card>
);
}
新问题是,当我尝试登录时,我被重定向到 http://localhost/api/auth/error
并且我收到了该错误:
404 | This page could not be found.
我是不是做错了什么?
经过几个小时的研究,我终于找到了 very recent Github discussion concerning the same problem。
在 NextAuth v4 中使用自定义基本路径的解决方案:
编辑您的 _app.tsx
并使用 <SessionProvider>
上的道具 basePath
定义您的基本路径,这是我使用自定义路径 /espace-personnel
的最终代码:
function App({ Component, pageProps: { session, ...pageProps} }: AppProps) {
return (
<SessionProvider session={session} basePath="/espace-personnel/api/auth">
<Component {...pageProps} />
</SessionProvider>
)
}
export default App
如果您对多个区域或自定义基本路径使用 next.js 身份验证,则需要进行一些更改以使 NextAuth.js 意识到这一点
1- 更新其余 api 路径基础,.env 文件
NEXTAUTH_URL=https://example.com
成为
NEXTAUTH_URL=https://example.com/{zone name or basePath}/api/auth
2-更新客户端api路径基础,_app.tsx
<SessionProvider session={pageProps.session}>
成为
<SessionProvider session={pageProps.session} basePath="/{zone name or basePath}/api/auth">
上下文
我正在使用 NextJS v12.0.7
、React v17.0.2
、NextAuth v4.1.0
和 Typescript v4.3.5
。
我想基于 NextAuth documentation 创建一个简单的身份验证系统,并在登录后重定向到主页,所以我在 pages/api/auth
文件夹中创建了一个名为 [...nextauth].ts
的文件包含以下代码部分:
export default NextAuth({
providers: [
CredentialsProvider({
id: "credentials",
name: "Login",
credentials: {
username: { type: "email" },
password: { type: "password" },
},
async authorize(credentials) {
// [...]
},
}),
],
// [...]
callbacks: {
// [...]
redirect({ url, baseUrl }) {
console.log("redirect - url ", url, "baseUrl ", baseUrl); // This is what I was checking
if(url.startsWith(baseUrl)) {
return url
} else if(url.startsWith("/")) {
return new URL(url, baseUrl).toString();
}
return baseUrl;
}
},
})
对于我的 NextJS 项目,我使用了 next.config.js
文件中定义的基本路径 /espace-personnel
,所以我在 .env.local
文件中定义了 NEXTAUTH_URL
NEXTAUTH_URL
37=]:
NEXTAUTH_URL=http://localhost/espace-personnel/api/auth
我的问题
我在重定向回调中检查 url
和 baseUrl
变量的地方,我可以看到我的 NEXTAUTH_URL
变量定义不正确,或者我误解了一些东西。
这是 console.log("redirect - url ", url, "baseUrl ", baseUrl);
的结果:
redirect - url http://localhost:3000 baseUrl http://localhost
我已经做过研究,但在 Google 或 Whosebug 上找不到像我这样的案例,我是 NextAuth 的新手,所以我可能误解了一些东西。有人知道我做错了什么吗?
编辑 (15/01/2022)
再三考虑后,我决定直接使用 process.env.NEXTAUTH_URL 检查我的 env 变量,所以我在之前的 console.log()
:
console.log("NEXTAUTH_URL", process.env.NEXTAUTH_URL)
结果如下:
NEXTAUTH_URL http://localhost/espace-personnel/api/auth
所以,事实上,这不是定义 NEXTAUTH_URL 的问题,我想我对 NextAuth 的工作方式有一些误解,我会继续尝试找到解决我的问题的方法并在那里分享我在找东西。
编辑 (16/01/2022)
经过一些研究,我发现我们可以使用 signIn 方法传递 callbackUrl,所以我在 [...nextauth].ts
中定义了我的页面:
pages: {
signIn: process.env.NEXT_PUBLIC_BASE_URL + '/connexion',
signOut: process.env.NEXT_PUBLIC_BASE_URL + '/deconnexion',
error: process.env.NEXT_PUBLIC_BASE_URL + '/connexion/erreur', // Error code passed in query string as ?error=
},
这是我的登录表单代码:
import React, { useState } from "react";
import Alert from "../../ui/Alert/Alert";
import Button from "../../ui/Button/Button";
import Card from "../../ui/Card/Card";
import Divider from "../../ui/Divider/Divider";
import { getCsrfToken, signIn } from "next-auth/react";
import Input from "../../ui/Input/Input";
import styles from "./LoginForm.module.scss";
import Router from 'next/router';
type TAlertTitle = string;
type TAlertMessage = string;
type TAlertType = "info" | "warning" | "success" | "error";
export default function LoginForm({ csrfToken }: { csrfToken: string }) {
const [alertTitle, setAlertTitle] = useState<TAlertTitle>("Information");
const [alertMessage, setAlertMessage] = useState<TAlertMessage>("Juste un exemple");
const [alertType, setAlertType] = useState<TAlertType>("info");
async function onSubmit(event: React.SyntheticEvent<HTMLFormElement>) {
const target = event.target as typeof event.target & {
username: { value: string },
password: { value: string },
};
// Login attempt
const result = signIn('credentials', {
callbackUrl: process.env.NEXT_PUBLIC_BASE_URL,
username: target.username.value,
password: target.password.value
});
console.log(result);
event.preventDefault();
}
return (
<Card className={styles.card}>
<p className={'textSize40 fontWeightExtraBold textAlignCenter'}>
Connexion à votre espace personnel
</p>
<Divider className={styles.divider} />
<form onSubmit={onSubmit}>
<Alert title={alertTitle} message={alertMessage} type={alertType}></Alert>
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
<Input id="username" name="username" className="width100" type="email" autoComplete="email" placeholder="Adresse mail" leftIconLib="line-awesome" leftIcon="envelope" required />
<Input id="password" name="password" className="width100" type="password" autoComplete="current-password" placeholder="Mot de passe" leftIconLib="line-awesome" leftIcon="key" required />
<Button className="width100" theme="accent" type="submit">Se connecter</Button>
<Button className="width100" type="submit">Identifiants oubliés</Button>
</form>
</Card>
);
}
新问题是,当我尝试登录时,我被重定向到 http://localhost/api/auth/error
并且我收到了该错误:
404 | This page could not be found.
我是不是做错了什么?
经过几个小时的研究,我终于找到了 very recent Github discussion concerning the same problem。
在 NextAuth v4 中使用自定义基本路径的解决方案:
编辑您的 _app.tsx
并使用 <SessionProvider>
上的道具 basePath
定义您的基本路径,这是我使用自定义路径 /espace-personnel
的最终代码:
function App({ Component, pageProps: { session, ...pageProps} }: AppProps) {
return (
<SessionProvider session={session} basePath="/espace-personnel/api/auth">
<Component {...pageProps} />
</SessionProvider>
)
}
export default App
如果您对多个区域或自定义基本路径使用 next.js 身份验证,则需要进行一些更改以使 NextAuth.js 意识到这一点
1- 更新其余 api 路径基础,.env 文件
NEXTAUTH_URL=https://example.com
成为
NEXTAUTH_URL=https://example.com/{zone name or basePath}/api/auth
2-更新客户端api路径基础,_app.tsx
<SessionProvider session={pageProps.session}>
成为
<SessionProvider session={pageProps.session} basePath="/{zone name or basePath}/api/auth">