使用 Next-Auth 和 MongoDB 进行凭据身份验证 - 第 1 部分

2025-06-08

使用 Next-Auth 和 MongoDB 进行凭据身份验证 - 第 1 部分

身份验证有时会比较复杂,因为我们需要考虑很多因素,例如会话管理、保护多个路由/页面、哈希密码、注册和登录时验证用户凭证等。此外,从头创建身份验证可能非常繁琐。

如果您正在使用 Next.JS,那么您应该尝试使用Next-Auth,因为它提供了许多身份验证方案,如 JWT、cookie 等。并且还可以使用第三方身份验证提供商,如 Google、Facebook,甚至 Discord(是的!)。

此外,next-auth 有助于会话管理,以便服务器不容易被欺骗。

除了提供商之外,我们还将研究根据用户凭证(如电子邮件和密码)设置身份验证。

身份验证期间需要考虑的事项

  1. 客户端表单验证
  2. 服务器表单值验证
  3. 出于显而易见的原因,在注册时对用户密码进行哈希处理
  4. 存储到数据库中
  5. 登录时检查哈希密码
  6. 保护未经身份验证的用户的路由
  7. 前端和后端的正确错误处理

我们需要的包

我使用 Next.js 作为演示的框架。

与此同时

  • next-auth用于身份验证
  • bycryptjs用于对密码进行哈希处理
  • MongoDB函数

笔记

这不是前端教程,所以我不会介绍任何有关成功事件和/或 CSS 内容的通知。

网站脚手架

该网站非常简单,由 4 个页面组成,显然还有一个导航栏,以便更好地演示:

  • 主页

主页

  • 登录/注册页面

登录/注册页面

  • 修改密码页面

修改密码页面

安装包并设置数据库

npm i next-auth mongodb bcryptjs
Enter fullscreen mode Exit fullscreen mode

在安装过程中,我们将在他们的网站上注册一个免费的 MongoDB 帐户。

.env.local现在,我们可以使用他们仪表板上的连接代码连接到该数据库。为了获得更精细、更安全的代码,我们应该使用文件内部的 MongoURL 。

注册路线

在登录之前,用户需要注册特定网站。NextJS 允许我们pages/api使用 NodeJS 环境在文件夹中编写 API 代码。它也将遵循相同的文件夹结构路由。

对于注册路由,我们将创建一个路由pages/api/auth/signup.js。我们还需要确保只接受POST方法,不接受其他任何方法。

注册路线中要做的事情

  • 获取用户凭证
  • 证实
  • 发送错误代码(如果有)
  • 连接到数据库
  • 检查是否有任何现有用户具有相同的电子邮件地址
  • 使用 bycrypt js 对密码进行哈希处理

bycrypt js在密码散列期间返回一个Promise ,因此我们需要等待响应。

password: await hash(password, 12)
//hash(plain text, no. of salting rounds)
Enter fullscreen mode Exit fullscreen mode
  • 如果一切顺利,则发送响应并关闭与数据库的连接
import { MongoClient } from 'mongodb';
import { hash } from 'bcryptjs';
async function handler(req, res) {
    //Only POST mothod is accepted
    if (req.method === 'POST') {
        //Getting email and password from body
        const { email, password } = req.body;
        //Validate
        if (!email || !email.includes('@') || !password) {
            res.status(422).json({ message: 'Invalid Data' });
            return;
        }
        //Connect with database
        const client = await MongoClient.connect(
            `mongodb+srv://${process.env.MONGO_USER}:${process.env.MONGO_PASS}@${process.env.MONGO_CLUSTER}.n4tnm.mongodb.net/${process.env.MONGO_DB}?retryWrites=true&w=majority`,
            { useNewUrlParser: true, useUnifiedTopology: true }
        );
        const db = client.db();
        //Check existing
        const checkExisting = await db
            .collection('users')
            .findOne({ email: email });
        //Send error response if duplicate user is found
        if (checkExisting) {
            res.status(422).json({ message: 'User already exists' });
            client.close();
            return;
        }
        //Hash password
        const status = await db.collection('users').insertOne({
            email,
            password: await hash(password, 12),
        });
        //Send success response
        res.status(201).json({ message: 'User created', ...status });
        //Close DB connection
        client.close();
    } else {
        //Response for other than POST method
        res.status(500).json({ message: 'Route not valid' });
    }
}

export default handler;
Enter fullscreen mode Exit fullscreen mode

现在我们的注册路线已经到位,是时候将前端连接到后端了。

发布注册表

import { signIn } from 'next-auth/client';
//...
const onFormSubmit = async (e) => {
        e.preventDefault();
        //Getting value from useRef()
        const email = emailRef.current.value;
        const password = passwordRef.current.value;
        //Validation
        if (!email || !email.includes('@') || !password) {
            alert('Invalid details');
            return;
        }
        //POST form values
        const res = await fetch('/api/auth/signup', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                email: email,
                password: password,
            }),
        });
        //Await for data for any desirable next steps
        const data = await res.json();
        console.log(data);
    };
//...
Enter fullscreen mode Exit fullscreen mode

有了注册登录后,我们来处理登录逻辑。

使用 Next-Auth 登录

Next-Auth 为我们提供了客户端 API以及REST API

NextAuth.js 客户端库可以轻松地与 React 应用程序的会话进行交互。

NextAuth.js 公开了一个由 NextAuth.js 客户端使用的REST API 。

我们将使用两者来登录用户。

要将 NextAuth.js 添加到项目中,请创建一个名为 的[...nextauth].js文件pages/api/auth

所有请求/api/auth/*(登录、回调、退出等)将自动由 NextAuth.js 处理。

在 next-auth 的帮助下,我们需要实现自己的登录逻辑来检查数据库中存储的用户。

签到路线中要做的事情:

  • 配置使用 JWT
  • 从下一个身份验证指定提供商(凭证)

如需更多提供商,请查看

  • 连接到数据库
  • 检查用户是否存在
  • 发送错误响应(如果有)
  • 将散列密码与存储在数据库中的密码进行比较
  • 发送回复
  • 关闭数据库连接

[...nextauth].js

import NextAuth from 'next-auth';
import Providers from 'next-auth/providers';
import { MongoClient } from 'mongodb';
import { compare } from 'bcryptjs';

export default NextAuth({
    //Configure JWT
    session: {
        jwt: true,
    },
    //Specify Provider
    providers: [
        Providers.Credentials({
            async authorize(credentials) {
                //Connect to DB
                const client = await MongoClient.connect(
                    `mongodb+srv://${process.env.MONGO_USER}:${process.env.MONGO_PASS}@${process.env.MONGO_CLUSTER}.n4tnm.mongodb.net/${process.env.MONGO_DB}?retryWrites=true&w=majority`,
                    { useNewUrlParser: true, useUnifiedTopology: true }
                );
                //Get all the users
                const users = await client.db().collection('users');
                //Find user with the email  
                const result = await users.findOne({
                    email: credentials.email,
                });
                //Not found - send error res
                if (!result) {
                    client.close();
                    throw new Error('No user found with the email');
                }
                //Check hased password with DB password
                const checkPassword = await compare(credentials.passowrd, result.passowrd);
                //Incorrect password - send response
                if (!checkPassword) {
                    client.close();
                    throw new Error('Password doesnt match');
                }
                //Else send success response
                client.close();
                return { email: result.email };
            },
        }),
    ],
});
Enter fullscreen mode Exit fullscreen mode
链接:https://dev.to/dawnind/authentication-with-credentials-using-next-auth-and-mongodb-part-1-m38
PREV
Flask REST API:Flask 基础知识
NEXT
Go:数组和切片,深入研究。