我在登录过程中使用NextAuth.js凭据提供程序。登录时,我在try-catch块中捕获错误,并相应地设置错误状态,但我还没有在任何地方显示错误状态。即使我捕获了错误,在尝试登录时仍会抛出401 unauthorized。我使用了错误的凭据,因此预期会出现名为CredentialsSignin的错误,但我得到了该错误。但另外我每次都得到401。问题是我无法检测到它被扔到哪里,这可能是我无法处理它的原因。
下面是我的自定义登录页面的代码:
import { InferGetServerSidePropsType } from "next"
import { CtxOrReq } from "next-auth/client/_utils";
import { getCsrfToken, getSession, signIn } from "next-auth/react"
import { useRouter } from "next/router";
import { useCallback, useEffect, useState } from "react";
import { useFormik } from "formik"
import * as Yup from "yup"
export default function Login({ csrfToken }: InferGetServerSidePropsType<typeof getServerSideProps>) {
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const router = useRouter()
type Credentials = {
email: string
password: string
}
let credentials: Credentials;
const handleLogin = useCallback(async (credentials) => {
if (!credentials.email) {
return setError('email is missing')
}
if (!credentials.password) {
return setError('password is missing')
}
try {
setLoading(true)
const response: any = await signIn('credentials', { ...credentials, redirect: false }) // find right type
if (response.error && response.error === 'CredentialsSignin') {
setError('email or password are wrong')
} else {
setError('')
router.push('/')
}
} catch {
setError('login failed')
} finally {
setLoading(false)
}
}, [router])
const formik = useFormik({
initialValues: {
email: "",
password: ""
},
validationSchema: Yup.object({
email: Yup.string()
.required("email address is required"),
password: Yup.string()
.required("password is required")
}),
onSubmit: values => {
credentials = {
email: values.email,
password: values.password
}
handleLogin(credentials)
}
})
return (
<form onSubmit={formik.handleSubmit} noValidate>
<input name="csrfToken" type="hidden" defaultValue={csrfToken} />
<label>
Email
<input
name="email"
type="email"
value={formik.values.email}
onChange={formik.handleChange}
onBlur={formik.handleBlur} />
</label>
{formik.touched.email && formik.errors.email && <p>{formik.errors.email}</p>}
<label>
Password
<input
name="password"
type="password"
value={formik.values.password}
onChange={formik.handleChange}
onBlur={formik.handleBlur} />
</label>
{formik.touched.password && formik.errors.password && <p>{formik.errors.password}</p>}
<button type="submit">Login</button>
</form>
)
}
export async function getServerSideProps(context: CtxOrReq | undefined) {
const session = await getSession(context)
if (session) {
return {
redirect: { destination: '/' }
}
}
return {
props: {
csrfToken: await getCsrfToken(context)
},
}
}
下面是我的[... nextauth].ts API页面的代码:
import NextAuth from 'next-auth'
import { PrismaAdapter } from '@next-auth/prisma-adapter'
import { prisma } from '../../../prisma/prisma_client'
import CredentialsProvider from "next-auth/providers/credentials"
import { compare } from 'bcryptjs'
export default NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
CredentialsProvider({
name: "Credentials",
credentials: {
email: {},
password: {}
},
async authorize(credentials) {
if (!credentials) {
return null
}
const { email } = credentials
const { password } = credentials
const storedUser = await prisma.user.findUnique({
where: {
email
}, select: {
id: true,
email: true,
hashedPassword: true,
company: {
select: {
id: true,
name: true
}
}
}
})
if (!storedUser) {
return null
}
const user = {
id: storedUser?.id,
email,
comanyId: storedUser?.company?.id,
companyName: storedUser?.company?.name,
}
const validatePassword = await compare(password, storedUser.hashedPassword)
return validatePassword ? user : null
}
})
],
pages: {
signIn: '/login'
},
callbacks: {
async jwt({ token, user }) {
user && (token.user = user)
return token
},
async session({ session, token }) {
session.user = token.user
return session
}
},
session: {
strategy: "jwt",
maxAge: 30 * 24 * 60 * 60 // 30 days
}
})
2条答案
按热度按时间uklbhaso1#
请确保将API对象的“withCredentials”设置为“true”
fwzugrvs2#
遇到了同样的问题,并设法解决了它。下面的第一个代码块是有错误的版本,第二个代码块是工作版本。
因此,有几件事需要注意:
catch
和response
返回了相同的数据,因为我想确定问题是否是由返回的数据引起的。但事实并非如此,所以在工作版本中恢复了这一点。return
,promise中有return
。我的理解是,response
和catch
块本身就是函数,在内部块中返回不会传播值,从而由authorize
函数返回。换句话说,我什么也不返回--结果是401
。第一个