正在尝试为React JS / Next JS项目实现NextAuth.js。当前正在运行React JS 18.2.0、Next JS 13.0.6和NextAuth.js 4.18.0。
我正在使用服务器端渲染和部署在Vercel上的Next API调用。为了确定会话,我使用了getServerSideProps中的unstable_getServerSession,它工作正常。现在我想使用signIn方法登录具有凭据提供程序的用户。我的实现通过向URL添加一些参数来保持重定向到同一页面:
URL如下所示:https://example.com/api/auth/signin?callbackUrl=%2F
其中显示:
{"boyd":"","query":{"callbackUrl":"/"},"cookies":{"__Host-next-auth.csrf-token":"token...","__Secure-next-auth.callback-url":"url..."}}
没有会话被保存,我不知道发生了什么。我希望登录方法可以解决这个问题,但是我假设服务器端呈现阻止了调用来解决这个问题。
下面的代码描述了我如何实现它的过程:
所用表格:
<Box component="form" onSubmit={handleSubmit} sx={{ mt: 1 }}>
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
<TextField
margin="normal"
required
fullWidth
id="phone"
label="Phone Number"
name="phone"
onChange={(e) => setPhone(e.target.value)}
autoComplete="phone"
autoFocus
/>
<TextField
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
onChange={(e) => setPassword(e.target.value)}
autoComplete="current-password"
/>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Sign In
</Button>
</Box>
窗体句柄:
const [phone, setPhone] = useState("");
const [password, setPassword] = useState("");
const [submit, setSubmit] = useState(false);
{/* On submit use Next Auth signIn method */}
const handleSubmit = (e) => {
e.preventDefault();
setSubmit(true);
}
useEffect(() => {
if(submit){
signIn("credentials", {
callbackUrl: '/',
username: phone,
password: password,
})
}
}, [submit])
正在获取CSRF令牌:
export async function getServerSideProps(context) {
return {
props: {
csrfToken: await getCsrfToken(context),
},
}
}
以及[... nextauth].js配置:
export const authOptions = {
// Authentication providers
providers: [
CredentialsProvider({
// The name to display on the sign in form (e.g. 'Sign in with...')
id: 'credentials',
name: 'Credentials',
// The credentials is used to generate a suitable form on the sign in page.
// You can specify whatever fields you are expecting to be submitted.
// e.g. domain, username, password, 2FA token, etc.
// You can pass any HTML attribute to the <input> tag through the object.
credentials: {
username: { label: "Phone", type: "text" },
password: { label: "Password", type: "password" }
},
async authorize(credentials, req){
const user_data = await checkCredentials(credentials.username, credentials.password);
if(user_data.success){
return user_data.user;
} else{
return null;
}
}
}),
// ...add more providers here
],
adapter : PrismaAdapter(prisma),
session: {
// Choose how you want to save the user session.
// The default is `"jwt"`, an encrypted JWT (JWE) stored in the session cookie.
// If you use an `adapter` however, we default it to `"database"` instead.
// You can still force a JWT session by explicitly defining `"jwt"`.
// When using `"database"`, the session cookie will only contain a `sessionToken` value,
// which is used to look up the session in the database.
strategy: "jwt",
// Seconds - How long until an idle session expires and is no longer valid.
maxAge: 30 * 24 * 60 * 60, // 30 days
// Seconds - Throttle how frequently to write to database to extend a session.
// Use it to limit write operations. Set to 0 to always update the database.
// Note: This option is ignored if using JSON Web Tokens
updateAge: 24 * 60 * 60, // 24 hours
// The session token is usually either a random UUID or string, however if you
// need a more customized session token string, you can define your own generate function.
generateSessionToken: () => {
return uid(32);
}
},
callbacks: {
async signIn({ user, account, profile, email, credentials }) {
return Promise.resolve(true);
},
async redirect({ url, baseUrl }) {
return Promise.resolve(url);
},
async jwt({ token, user, account, profile, isNewUser }) {
return Promise.resolve(token);
},
async session({ session, token, user }) {
// Send properties to the client, like an access_token from a provider.
session.user.image = '';
return Promise.resolve(session);
},
async credentials({ user, account, profile }){
return Promise.resolve(true);
}
},
secret: process.env.NEXTAUTH_SECRET,
pages: {
signIn: '/login'
},
debug: false
}
如果你有任何关于如何解决这个问题的建议,让我知道:)
1条答案
按热度按时间ftf50wuq1#
我设法找出了问题所在。我的API文件夹中有一个index.js文件,给出了一个标准的ok回复。删除路由后,Vercel显示了访问/api/auth/* routes时的404个错误。原来我的vercel.json配置阻止了这些调用。删除vercel.json中的以下行后,一切正常: