NextAuth.js服务器端的signIn函数如何实现?重定向无法工作

ryoqjall  于 2022-12-23  发布在  其他
关注(0)|答案(1)|浏览(182)

正在尝试为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
}

如果你有任何关于如何解决这个问题的建议,让我知道:)

ftf50wuq

ftf50wuq1#

我设法找出了问题所在。我的API文件夹中有一个index.js文件,给出了一个标准的ok回复。删除路由后,Vercel显示了访问/api/auth/* routes时的404个错误。原来我的vercel.json配置阻止了这些调用。删除vercel.json中的以下行后,一切正常:

"rewrites": [{ "source": "/api/(.*)", "destination": "/api" }]

相关问题