Next-Auth 및 MongoDB를 사용하여 자격 증명으로 인증

로그인 인증 생성을 위해 Vercel의 Next-Auth 패키지를 사용할 것입니다. 여기 링크Next-Auth가 있습니다.

설치하자 터미널을 열고 실행

npm i next-auth


다음 단계는 Api 내부에 폴더를 생성하고 폴더 이름을 auth로 설정하고 auth 내부에서 새 파일 세트 파일 이름을 [...nextauth].js로 설정하는 것입니다. 모든 로그인, 로그아웃 및 인증 확인은 이 파일로 리디렉션되며 필요합니다. 그것을 처리하기 위해



Next-Auth를 가져와 시작하겠습니다.

import NextAuth from "next-auth";


그런 다음 기본 NextAuth를 내보내십시오. Object의 매개 변수로 Object를 허용하는 기능입니다. 일부 속성을 설정해야 합니다. 첫 번째 속성은 세션이고 세션 내에서 jwt를 전략으로 사용할 것입니다.

import NextAuth from "next-auth";

export default NextAuth({
  session: {
    strategy: "jwt",
  }
})



NextAuth 함수에 대한 다음 설정은 콜백이 개체이고 함수를 정의해야 하는 내부에서 jwt입니다. 비동기 함수이고 jwt는 두 개의 매개변수를 허용합니다. 첫 번째 매개변수는 세션이고 두 번째 매개변수는 사용자입니다. jwt 함수 내부에서 사용자 ID를 확인합니다. 존재한다면 토큰 ID를 사용자 ID로 채우고 토큰을 반환하십시오.

사용자 ID는 NextAuth 수명 주기의 데이터베이스 및 토큰에서 가져옵니다.

import NextAuth from "next-auth";

export default NextAuth({
  session: {
    strategy: "jwt",
  },
  callbacks: {
    async jwt({ token, user }) {
      if (user?._id) token._id = user._id;
      if (user?.isAdmin) token.isAdmin = user.isAdmin;
      return token;
    },
  },
})



다음 콜백에서 우리는 두 개의 매개변수 세션과 토큰을 받아들이는 세션 함수를 정의할 것입니다.

세션 함수에서 토큰이 존재하는지 확인하고 토큰으로 세션을 채우고 종료 세션을 반환합니다.

import NextAuth from "next-auth";

export default NextAuth({
  session: {
    strategy: "jwt",
  },
  callbacks: {
    async jwt({ token, user }) {
      if (user?._id) token._id = user._id;
      if (user?.isAdmin) token.isAdmin = user.isAdmin;
      return token;
    },
    async session({ session, token }) {
      if (token?._id) session.user._id = token._id;
      if (token?.isAdmin) session.user.isAdmin = token.isAdmin;
      return session;
    },
  },
})



다음 설정은 제공자가 배열이고 우리가 사용할 제공자가 CredentialsProvider임을 정의하는 것입니다. 우리는 Github 인증 또는 Google 로그인을 사용하지 않고 MongoDB 데이터베이스를 기반으로 사용자를 인증할 것입니다.

매개 변수에서 CredentialsProvider를 사용하여 개체를 정의하고 내부 정의 권한 부여 기능은 자격 증명을 매개 변수로 받아들이는 비동기 함수입니다. 데이터베이스에 연결하고 자격 증명 매개 변수의 전자 메일을 기반으로 데이터베이스에서 사용자를 찾아야 합니다.
config 폴더에서 ConnectDB를 가져와야 하고 models 폴더에서 User를 가져와야 합니다.

다음 단계는 사용자가 존재하는 경우 사용자와 비밀번호를 함께 확인하는 것입니다. 이는 해당 이메일을 가진 사용자가 있음을 의미하고 비밀번호가 올바른지 확인한 다음 개체를 반환해야 합니다. 개체는 데이터베이스에서 가져옵니다.

import NextAuth from "next-auth";
import connectDB from "../../../config/db";
import CredentialsProvider from "next-auth/providers/credentials";
import User from "../../../models/User";
import bcrypt from "bcryptjs";

export default NextAuth({
  session: {
    strategy: "jwt",
  },

  callbacks: {
    async jwt({ token, user }) {
      if (user?._id) token._id = user._id;
      if (user?.isAdmin) token.isAdmin = user.isAdmin;
      return token;
    },
    async session({ session, token }) {
      if (token?._id) session.user._id = token._id;
      if (token?.isAdmin) session.user.isAdmin = token.isAdmin;
      return session;
    },
  },
  providers: [
    CredentialsProvider({
      async authorize(credentials) {
        connectDB();
        const user = await User.findOne({ email: credentials.email });
        if (user && bcrypt.compareSync(credentials.password, user.password)) {
          console.log(user);
          return {
            _id: user._id,
            name: user.name,
            email: user.email,
            isAdmin: user.isAdmin,
          };
        }
        throw new Error("Invalid Email or Password");
      },
    }),
  ],
});



놀랍게도, 로그인 기능을 구현하고 NextAuth 기능을 구성했습니다. 다음 단계는 제출을 처리해야 하는 페이지 내부의 로그인 페이지로 이동하는 것입니다.

import Link from "next/link";
import React, { useEffect, useState } from "react";
import Layout from "../components/Layout";
import { useForm } from "react-hook-form";
import { signIn, useSession } from "next-auth/react";
import { toast } from "react-toastify";
import { getError } from "../utils/error";
import { useRouter } from "next/router";

const login = () => {
  const { data: session } = useSession();
  const router = useRouter();

  useEffect(() => {
    if (session?.user) router.push("/");
  }, [session, router]);

  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();
  const handleLogin = async ({ email, password }) => {
    try {
      const result = await signIn("credentials", {
        redirect: false,
        email,
        password,
      });
      if (result.error) toast.error(result.error);
    } catch (err) {
      toast.error(getError(err));
    }
  };
  const handleError = (errors) => {};

  const loginOptions = {
    email: {
      required: "Email is required",
      pattern: {
        value: /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$/i,
        message: "Email not valid",
      },
    },
    password: {
      required: "Password is required",
    },
  };

  return (
    <Layout title="Login">
      <form
        className="mx-auto max-w-screen-sm"
        onSubmit={handleSubmit(handleLogin, handleError)}
      >
        <div className="flex flex-col mt-4 mb-5">
          <h1 className="text-[30px] text-[#06283D] font-medium">Login</h1>
        </div>

        <div className="flex flex-col mb-3">
          <label
            htmlFor="email"
            className="text-[17px] text-[#06283D] font-medium mb-2"
          >
            Email
          </label>
          <input
            type="text"
            id="email"
            {...register("email", loginOptions.email)}
            autoFocus
          />
          {errors?.email && (
            <p className="text-[16px] text-red-500">{errors.email.message}</p>
          )}
        </div>
        <div className="flex flex-col mb-3">
          <label
            htmlFor="password"
            className="text-[17px] text-[#06283D] font-medium mb-2"
          >
            Password
          </label>
          <input
            type="password"
            id="password"
            {...register("password", loginOptions.password)}
            autoFocus
          />
          {errors?.password && (
            <p className="text-[16px] text-red-500">
              {errors.password.message}
            </p>
          )}
        </div>
        <button className="bg-[#06283D] px-5 py-3 text-white font-medium text-center rounded-sm">
          Login
        </button>
        <div className="flex flex-col mt-4 text-[#06283D] text-[16px] font-medium">
          Don't have an account, <br />
          <Link href="/register">Register</Link>
        </div>
      </form>
    </Layout>
  );
};

export default login;

좋은 웹페이지 즐겨찾기