Explore o novo chatbot do Developer Center! O MongoDB AI chatbot pode ser acessado na parte superior da sua navegação para responder a todas as suas perguntas sobre o MongoDB .

Junte-se a nós no Amazon Web Services re:Invent 2024! Saiba como usar o MongoDB para casos de uso de AI .
Desenvolvedor do MongoDB
Central de desenvolvedor do MongoDBchevron-right
Idiomaschevron-right
TypeScriptchevron-right

Autenticação NextAuth.js com MongoDB

Ahmed Bouchefra10 min read • Published Aug 30, 2024 • Updated Aug 30, 2024
MongooseNext.jsTypeScriptJavaScript
APLICATIVO COMPLETO
Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
NextAuth.js é uma biblioteca de autenticação robusta construída para aplicativos Next.js. O NextAuth.js simplifica a integração de funcionalidades de autenticação e oferece compatibilidade com vários métodos de autenticação, incluindo provedores OAuth (Google, Github etc.), logins por e-mail/senha e muito mais.
Este tutorial mostra como configurar o NextAuth.js para autenticação de usuário com e-mail e senha em seu aplicativo Next.js 14 .
Você pode encontrar o código neste repositório do GitHub.

O que é Next-Auth?

Next-Auth é uma biblioteca de autenticação projetada para aplicativos Next.js especificamente. Simplificando, o Next-Auth facilita a adição de autenticação aos seus aplicativos Next.js. Ele fornece uma integração mais perfeita das funcionalidades de autenticação. O Next-Auth também oferece melhor compatibilidade com outros métodos de autenticação, como provedores OAuth (Google, Github, etc.).
O Next-Auth oferece um conjunto de APIs fáceis de usar e outros componentes que podem lidar com fluxos de autenticação muito complexos. Isso significa que os desenvolvedores podem se concentrar mais na criação de seus aplicativos.
O Next-Auth oferece pronto para uso, segurança de autenticação e gerenciamento de sessão integrado. É apropriado para aplicativos de todos os tamanhos e funciona bem com ambientes de computação de borda e sem servidor. Ele também oferece suporte completo ao Typescript , para uma melhor experiência do desenvolvedor.

Requisitos

Antes de começarmos, certifique-se de ter os seguintes pré-requisitos:
  • Node.js v20: Verifique se você tem o Node.js instalado em sua máquina. Você pode baixá-lo do site oficial.
  • React e Next.js 14: uma compreensão básica do React e Next.js 14 é útil para este tutorial.
  • (Opcional) Tenha o MongoDB Community Edition 7.0 instalado e em execução.
Certifique-se de que o serviço mongodb-community foi iniciado localmente. Como alternativa, você pode usar um MongoDB Atlas clustergratuito para sempre.

Criando o projeto Next.js

Vamos criar um novo projeto Next.js usando o seguinte comando no seu terminal:
1npx create-next-app@latest mongodb-auth
Responda às perguntas da seguinte forma:
1create-next-app@14.2.3
2Ok to proceed? (y) y
3✔ Would you like to use TypeScript? … Yes
4✔ Would you like to use ESLint? … Yes
5✔ Would you like to use Tailwind CSS? … Yes
6✔ Would you like to use `src/` directory? … No
7✔ Would you like to use App Router? (recommended) … Yes
8✔ Would you like to customize the default import alias (@/*)? … No
Após as instruções, create-next-app criará uma pasta com o nome do projeto e instalará as dependências necessárias.

Instalando dependências

Navegue dentro do seu projeto e instale as seguintes dependências:
1cd mongo-auth
2npm install next-auth bcryptjs mongoose
3npm install –-save-dev @types/bcryptjs
O pacote próximo-auth fornece funcionalidades de autenticação para aplicativos Next.js. O pacote próximo-autenticação também oferece suporte integrado para vários fornecedores de autenticação e permite fácil integração com seu aplicativo.
A biblioteca bcryptjs fornece funções para hash de senhas usando o algoritmo bcrypt. É comumente usado para armazenar senhas com segurança em bancos de dados, gerando hashes de senha salgados.
Mongoose é uma biblioteca de modelagem de dados de objetos (ODM) para MongoDB e Node.js. Ele fornece uma solução simples e baseada em esquema para modelar os dados do aplicativo, facilitando o trabalho com bancos de dados MongoDB.
Depois de instalar essas dependências, você terá as ferramentas e bibliotecas necessárias para configurar os recursos de autenticação em seu aplicativo Next.js, integrá-lo ao MongoDB, criptografar senhas com segurança e definir modelos de dados usando o Mongoose.

Conectando ao MongoDB

Depois de instalar as dependências, é hora de conectar ao MongoDB. Crie um arquivo.env.local na raiz do seu projeto e adicione sua connection string do MongoDB:
1MONGODB_URI=mongodb://127.0.0.1:27017/mydb
Observação: se você estiver se conectando a um cluster do MongoDB Atlas, poderá encontrar sua string de conexão no painel do Atlas.
Crie um arquivolib/mongodb.ts e adicione o seguinte código para conectar a um MongoDB database utilizando o mongoose:
1import mongoose from "mongoose";
2const { MONGODB_URI } = process.env;
3export const connectDB = async () => {
4 try {
5 const { connection } = await mongoose.connect(MONGODB_URI as string);
6 if (connection.readyState === 1) {
7 return Promise.resolve(true);
8 }
9 } catch (error) {
10 console.error(error);
11 return Promise.reject(error);
12 }
13};
Estamos importando a bibliotecamongoose, que é uma biblioteca ODM Node.js popular para o MongoDB. Em seguida, recuperamos o URI MongoDB das variáveis de ambiente. Em seguida, definimos uma função assíncrona denominada connectDB que se conecta ao MongoDB database utilizando o URI obtido das variáveis de ambiente.
Dentro da funçãoconnectDB, usamos um blocotry...catch para lidar com quaisquer erros potenciais que podem ocorrer durante o processo de conexão do banco de dados. Dentro do blocotry, usamos o mongoose.connect() para estabelecer uma conexão com o MongoDB database utilizando o URI fornecido. Se a conexão for bem-sucedida, resolvemos a promessa com um valor de true.
Se ocorrer algum erro durante o processo de conexão, ele será capturado pelo blococatch. Nesse caso, registramos o erro no console e rejeitamos a promessa com o erro capturado.
Em seguida, crie um arquivomodels/User.tse comece adicionando as seguintes importações:
1import mongoose, { Schema, model } from "mongoose";
Adicione a interface do usuário:
1export interface UserDocument {
2 _id: string;
3 email: string;
4 password: string;
5 name: string;
6 phone: string;
7 image: string;
8 createdAt: Date;
9 updatedAt: Date;
10}
Adicione o esquema de usuário:
1const UserSchema = new Schema<UserDocument>({
2 email: {
3 type: String,
4 unique: true,
5 required: [true, "Email is required"],
6 match: [
7 /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/,
8 "Email is invalid",
9 ],
10 },
11 password: {
12 type: String,
13 required: true
14 },
15 name: {
16 type: String,
17 required: [true, "Name is required"]
18 }
19 },
20 {
21 timestamps: true,
22 }
23);
Isso define um esquema Mongoose para um documento de usuário. O UserSchema especifica a estrutura e as regras de validação para dados de usuário armazenados em uma coleção MongoDB.
Por fim, exporte o modelo do usuário:
1const User = mongoose.models?.User || model<UserDocument>('User', UserSchema);
2export default User;
Isso garante que o modelo de usuário seja definido e esteja disponível para uso no aplicativo, recuperando um modelo existente ou criando um novo com base no esquema especificado.

Configurando NextAuth.js

Primeiro, precisamos de uma chave secreta NextAuth. Esta chave secreta é usada para criptografar tokens JWT e dados de sessão. Você pode obtê-lo simplesmente executando este comando em seu terminal e ele gerará uma chave aleatória para você:
1npx auth secret
Você precisa copiar o segredo para seu arquivo.env:
1AUTH_SECRET=bVNtF3X1k0QwTD9bx5xUUHOFWAwMXwNdvoF9D8AdgtE=
Crie um arquivolib/auth.tse comece adicionando as seguintes importações:
1import { connectDB } from "@/lib/mongodb";
2import User from "@/models/User";
3import type { NextAuthOptions } from "next-auth";
4import credentials from "next-auth/providers/credentials";
5import bcrypt from "bcryptjs";
Defina um objeto NextAuth options da seguinte maneira:
1export const authOptions: NextAuthOptions = {
2 providers: [
3 credentials({
4 name: "Credentials",
5 id: "credentials",
6 credentials: {
7 email: { label: "Email", type: "text" },
8 password: { label: "Password", type: "password" },
9 },
10 async authorize(credentials) {},
11 }),
12 ],
13 session: {
14 strategy: "jwt",
15 }
16};
Na funçãoauthorize(), adicione o seguinte código:
1await connectDB();
2const user = await User.findOne({
3 email: credentials?.email,
4}).select("+password");
5
6if (!user) throw new Error("Wrong Email");
7
8const passwordMatch = await bcrypt.compare(
9 credentials!.password,
10 user.password
11);
12
13if (!passwordMatch) throw new Error("Wrong Password");
14return user;
Este código verifica as credenciais do usuário (e-mail e senha) em relação às armazenadas em um MongoDB database. Ele garante que as credenciais fornecidas sejam válidas antes de permitir que o usuário prossiga com a autenticação.
Em seguida, crie um app/api/auth/[...nextauth]/route.ts arquivo e adicione o seguinte código:
1import { authOptions } from "@/lib/auth";
2import NextAuth from "next-auth";
3const handler = NextAuth(authOptions);
4export { handler as GET, handler as POST };
Esse código importa as opções de autenticação de seu módulo, inicializa o manipulador de autenticação usando essas opções e exporta o manipulador a ser usado para solicitaçõesGET e POST nas rotas da API.

Criando uma ação de servidor para registrar usuários

Em Next.js, uma ação do servidor refere-se a qualquer lógica ou funcionalidade que seja executada no lado do servidor antes de renderizar a página. Isso pode incluir tarefas como buscar dados de uma API externa, acessar um banco de dados ou realizar verificações de autenticação.
Em nosso caso, criaremos uma ação de servidor para registrar usuários. Dentro da raiz do seu projeto, crie um arquivoactions/register.ts e comece adicionando as seguintes importações:
1"use server"
2import { connectDB } from "@/lib/mongodb";
3import User from "@/models/User";
4import bcrypt from "bcryptjs";
A diretiva "use server", colocada no início do arquivo, instrui Next.js a tratar a(s) função(ões) como uma ação do servidor. Essa função pode ser chamada a partir de componentes do lado do cliente, mas é executada no servidor.
Exporte uma ação de servidor da seguinte maneira:
1export const register = async (values: any) => {
2 const { email, password, name } = values;
3
4 try {
5 await connectDB();
6 const userFound = await User.findOne({ email });
7 if(userFound){
8 return {
9 error: 'Email already exists!'
10 }
11 }
12 const hashedPassword = await bcrypt.hash(password, 10);
13 const user = new User({
14 name,
15 email,
16 password: hashedPassword,
17 });
18 const savedUser = await user.save();
19
20 }catch(e){
21 console.log(e);
22 }
23}
A funçãoregisterlida com o processo de registro de um novo usuário conectando-se ao MongoDB database, verificando os endereços de e-mail existentes, fazendo hash das senhas e salvando os dados do usuário no MongoDB database.

Criando páginas

Após configurar o NextAuth e implementar uma ação de servidor para registro de usuário, a próxima etapa é criar as páginas de login e registro.

Login page

Para começar, vamos nos concentrar na página de login. Crie um arquivo denominado app/login/page.tsx e comece importando as dependências necessárias:
1"use client";
2import { FormEvent, useState } from "react";
3import { signIn } from "next-auth/react";
4import { useRouter } from "next/navigation";
5import Link from "next/link";
A diretivause clienté usada para marcar o componente como código do lado do cliente. Isso significa que o código dentro desse escopo só será executado e estará disponível no ambiente do navegador do usuário, e não no servidor.
Defina uma função e exporte-a:
1export default function Login() {};
No corpo da função, comece adicionando o seguinte código:
1const [error, setError] = useState("");
2const router = useRouter();
Isso estabelece o gerenciamento de estado para mensagens de erro e acesso ao roteador do lado do cliente.
Adicione a funçãohandleSubmit()da seguinte forma:
1const handleSubmit = async (event: FormEvent<HTMLFormElement>) => {
2 event.preventDefault();
3 const formData = new FormData(event.currentTarget);
4 const res = await signIn("credentials", {
5 email: formData.get("email"),
6 password: formData.get("password"),
7 redirect: false,
8 });
9 if (res?.error) {
10 setError(res.error as string);
11 }
12 if (res?.ok) {
13 return router.push("/");
14 }
15};
Isso define uma função assíncrona que lida com o envio de formulários para o login do usuário. Ele evita o comportamento padrão do formulário, extrai credenciais de usuário do formulário usando FormData, tenta se conectar usando NextAuth.js, e lida com o login bem-sucedido redirecionando o usuário para a página inicial e com possíveis erros atualizando o estado de erro do componente.
Retorna o seguinte código JSX:
1return (
2 <section className="w-full h-screen flex items-center justify-center">
3 <form
4 className="p-6 w-full max-w-[400px] flex flex-col justify-between items-center gap-2
5 border border-solid border-black bg-white rounded"
6 onSubmit={handleSubmit}>
7 {error && <div className="text-black">{error}</div>}
8 <h1 className="mb-5 w-full text-2xl font-bold">Sign In</h1>
9 <label className="w-full text-sm">Email</label>
10 <input
11 type="email"
12 placeholder="Email"
13 className="w-full h-8 border border-solid border-black rounded p-2"
14 name="email" />
15 <label className="w-full text-sm">Password</label>
16 <div className="flex w-full">
17 <input
18 type="password"
19 placeholder="Password"
20 className="w-full h-8 border border-solid border-black rounded p-2"
21 name="password" />
22 </div>
23 <button className="w-full border border-solid border-black rounded">
24 Sign In
25 </button>
26
27 <Link
28 href="/register"
29 className="text-sm text-[#888] transition duration-150 ease hover:text-black">
30 Don't have an account?
31 </Link>
32 </form>
33 </section>
34);
Isso simplesmente cria um formulário que permite aos usuários inserir seu e-mail e senha para autenticação e fornece um link para navegar até a página de registro se ainda não tiverem uma conta.
Veja como é o formulário: formulário de inscrição

Página de registro

Em seguida, vamos criar a página de registro. Crie um arquivoapp/register/page.tsx e comece adicionando o seguinte código:
1"use client";
2import { FormEvent, useRef, useState } from "react";
3import { useRouter } from "next/navigation";
4import Link from "next/link";
5import { register } from "@/actions/register";
6
7
8export default function Register() {
9 const [error, setError] = useState<string>();
10 const router = useRouter();
11 const ref = useRef<HTMLFormElement>(null);
12}
Isso cria um componente do lado do cliente que inicializa o estado para tratamento de erros, utiliza o roteador Next.js para navegação e fornece uma referência ao elemento do formulário, que será criado abaixo, usando uma ref.
Adicione a funçãohandleSubmit():
1const handleSubmit = async (formData: FormData) => {
2 const r = await register({
3 email: formData.get("email"),
4 password: formData.get("password"),
5 name: formData.get("name")
6 });
7 ref.current?.reset();
8 if(r?.error){
9 setError(r.error);
10 return;
11 } else {
12 return router.push("/login");
13 }
14};
Isso define uma função assíncrona denominada handleSubmit, que é chamada quando um formulário é enviado. A função lida com o envio do formulário, incluindo a extração dos dados do formulário usando FormData, o registro do usuário chamando a ação do servidor de registro, o tratamento de erros e o redirecionamento do usuário para a página de login após o registro bem-sucedido. Caso contrário, ela define o erro que será exibido.
Retorna o seguinte código JSX:
1return(
2<section className="w-full h-screen flex items-center justify-center">
3 <form ref = {ref}
4 action={handleSubmit}
5 className="p-6 w-full max-w-[400px] flex flex-col justify-between items-center gap-2
6 border border-solid border-black bg-white rounded">
7 {error && <div className="">{error}</div>}
8 <h1 className="mb-5 w-full text-2xl font-bold">Register</h1>
9
10 <label className="w-full text-sm">Full Name</label>
11 <input
12 type="text"
13 placeholder="Full Name"
14 className="w-full h-8 border border-solid border-black py-1 px-2.5 rounded text-[13px]"
15 name="name"
16 />
17
18 <label className="w-full text-sm">Email</label>
19 <input
20 type="email"
21 placeholder="Email"
22 className="w-full h-8 border border-solid border-black py-1 px-2.5 rounded"
23 name="email"
24 />
25
26 <label className="w-full text-sm">Password</label>
27 <div className="flex w-full">
28 <input
29 type="password"
30 placeholder="Password"
31 className="w-full h-8 border border-solid border-black py-1 px-2.5 rounded"
32 name="password"
33 />
34 </div>
35
36 <button className="w-full border border-solid border-black py-1.5 mt-2.5 rounded
37 transition duration-150 ease hover:bg-black">
38 Sign up
39 </button>
40
41
42 <Link href="/login" className="text-sm text-[#888] transition duration-150 ease hover:text-black">
43 Already have an account?
44 </Link>
45 </form>
46</section>
47)
É assim que parece:
formulário de inscrição

Usando o provedor de sessão e exibindo o estado de autenticação

Nesta seção, demonstraremos como usar o SessionProvider no layout pai para garantir que o gerenciamento de sessão esteja disponível em todo o aplicativo. Recuperaremos o estado de autenticação da sessão e exibiremos dinamicamente um botão "Sign Out" se o usuário estiver autenticado, ou um botão "Sign In" se o usuário não estiver autenticado.
Crie um app/provider.tsx arquivo e adicione o seguinte código:
1"use client";
2
3import { SessionProvider } from "next-auth/react";
4
5type Props = {
6 children?: React.ReactNode;
7};
8
9export const Provider = ({ children }: Props) => {
10 return <SessionProvider>{children}</SessionProvider>;
11};
Atualize o app/layout.tsx com o provedor que criamos. Primeiro importe-o:
1import { Provider } from "./provider";
Em seguida, adicione da seguinte forma:
1export default function RootLayout({
2 children,
3}: Readonly<{
4 children: React.ReactNode;
5}>) {
6 return (
7 <html lang="en">
8 <Provider>
9 <body className={inter.className}>{children}</body>
10 </Provider>
11 </html>
12 );
13}
Atualize o arquivoapp/page.tsx da seguinte maneira:
1"use client";
2import { signOut, useSession } from "next-auth/react";
3import Link from "next/link";
4import { useRouter } from "next/navigation";
5
6export default function Home() {
7 const { status } = useSession();
8 const router = useRouter();
9
10 const showSession = () => {
11 if (status === "authenticated") {
12 return (
13 <button
14 className="border border-solid border-black rounded"
15 onClick={() => {
16 signOut({ redirect: false }).then(() => {
17 router.push("/");
18 });
19
20 }}
21 >
22 Sign Out
23 </button>
24 )
25 } else if (status === "loading") {
26 return (
27 <span className="text-[#888] text-sm mt-7">Loading...</span>
28 )
29 } else {
30 return (
31 <Link
32 href="/login"
33 className="border border-solid border-black rounded"
34 >
35 Sign In
36 </Link>
37 )
38 }
39 }
40 return (
41 <main className="flex min-h-screen flex-col items-center justify-center">
42 <h1 className="text-xl">Home</h1>
43 {showSession()}
44 </main>
45 );
46}
Atualize o arquivoapp/globals.csspara remover o CSS personalizado e manter apenas o seguinte:
1@tailwind base;
2@tailwind components;
3@tailwind utilities;

Teste

Você primeiro precisa se registrar a partir desta interface:
Interface de login
Você pode então fazer login a partir desta interface:
registrar interface
Você será redirecionado para a página inicial com o botão “Sign Out”, que aparece somente quando o usuário está logado, e você pode usá-lo para sair do aplicativo:
botão de saída

Conclusão

Neste tutorial, analisamos as etapas para configurar a autenticação NextAuth.js com o MongoDB como banco de dados de back-end. Começamos criando um novo projeto Next.js e instalando as dependências necessárias. Em seguida, estabelecemos uma conexão com o MongoDB usando o Mongoose e definimos um esquema de usuário para estruturar nossos dados de usuário.
Em seguida, configuramos NextAuth.js gerando uma chave secreta, definindo opções de autenticação e implementando a lógica de autorização para verificar as credenciais do usuário em relação ao MongoDB. Também criamos ações de servidor para o registro de usuários, lidando com operações de banco de dados com segurança no lado do servidor.
Depois de configurar a autenticação, criamos páginas de login e registro usando componentes React e as integramos ao NextAuth.js para autenticação. Lidamos com envios de formulários, tratamento de erros e redirecionamento de usuários com base no status da autenticação.
Por fim, atualizamos o layout para incluir um provedor de sessão para gerenciar sessões de usuário e garantir a exibição adequada do status de autenticação na página inicial.
Ao seguir essas etapas, você pode implementar efetivamente a autenticação em seu aplicativo Next.js usando o NextAuth.js e o MongoDB, fornecendo uma experiência segura e contínua para seus usuários e simplificando o processo de configuração da autenticação para desenvolvedores.
Quer continuar a conversa? Vá para a comunidade de desenvolvedores do MongoDB em seguida.
Principais comentários nos fóruns
Avatar do Comentarista do Fórum
Akash_Mishra1Akash Mishralast quarter

este código não está funcionando no modo de produção. está mostrando erro
O erro foi causado pela importação de 'mongoose/dist/browser.umd.js


Avatar do Comentarista do Fórum
Atlas_KotkarAtlas_Kotkar2 meses atrás

@Dvir_Ben_Ishay Olá, também estou enfrentando um problema exato dos últimos 7 dias. Não foi possível resolver esse problema. Você já acordou esse problema? Por favor, informe-me ou você pode me escrever em: trocanilkotkar793@mail.com

Veja mais nos fóruns

Ícone do FacebookÍcone do Twitterícone do linkedin
Avalie esse Tutorial
star-empty
star-empty
star-empty
star-empty
star-empty
Relacionado
Tutorial

Melhore Seus Aplicativos de AI : Amazon Web Services Ler mais, MongoDB e Typescript


Oct 10, 2024 | 9 min read
Tutorial

Introdução ao Deno 2.0 e MongoDB


Oct 22, 2024 | 13 min read
exemplo de código

Trends Analyser


Sep 11, 2024 | 1 min read
Tutorial

Usando Expo e Realm React Native com expo-dev-client


Aug 26, 2022 | 3 min read
Sumário