一、next-auth 身份验证凭据-使用电子邮件和密码注册登录

一、next-auth 身份验证凭据-使用电子邮件和密码注册登录

一、前言

近些时间需要在next 里面加入登录注册的功能遂整理了一下学习视频:
Next auth 身份验证凭据 - 使用电子邮件和密码注册和登录(NextJS app 路由)

二、前置准备

1、环境配置

  • Vscode

  • node环境配置

  • vercel 账户注册

  • github账户注册

2、相关库安装

(1)vercel 配置

  1. npm i -g vercel //安装vercel CLI

(2)Yarn 包管理配置

  1. npm i -g yarn //安装yarn

3、next项目初始化与创建

  1. yarn create next-app

在这里插入图片描述

  1. cd nextauth-review (这里面放你写的项目名)

  2. yarn dev //运行程序,在http://localhost:3000可以查看next项目的项目名在这里插入图片描述

到这里我们就基本完成了前置的准备工作,下面继续。

三、具体实现

1、github 仓库创建与链接

在这里插入图片描述

将新建的项目上传github

在这里插入图片描述

2、Vercel项目链接Vercel账户并部署

(1)项目上传vercel

  • vercel login //vercel 登录

  • Vercel //链接与上传

在这里插入图片描述

第三行输入n。最开始的时候不连接vercel项目。

注:后续如果项目更新了,要推送到vercel部署,可以通过输入vercel ,然后在第三行输入y,并输入第一步创建的项目名。

(2)项目创建并链接postgre 数据库

在这里插入图片描述

(3)本地化项目链接数据库准备

  1. vercel env pull .env.development.local

在这里插入图片描述
注释掉VERCEL,不注释掉就会强制使用https,但我们在本地调试所以说http会报错。正式运行再取消注释。

  1. openssl rand -base64 32 ,生成32位密码,并修改.env.development.local如下:

在这里插入图片描述

  1. yarn add @types/bcrypt 安装加密工具bcrypt

  2. yarn add @vercel/postgres 安装vercel postgres

  3. yarn add next-auth 安装next-auth

到这里该项目的数据库就配置好了,下面我们开始页面开发。

3、登录页面与注册页面的前端

(1)登录页面

新建login文件夹,并在其中新建page.tsx下面是具体的内容

export default function LoginPage(){
  return (
    <form className="flex flex-col gap-2 mx-auto max-w-md mt-10">
    <input name='email' className ="border border-black text-black" type="email" />
    <input name='password' className ="border border-black text-black" type="password" />
    <button type="submit">Login</button>
  </form>
  )
}

(1)注册页面

新建register文件夹,并在其中新建page.tsx下面是具体的内容

export default function LoginPage(){
  return (
    <form className="flex flex-col gap-2 mx-auto max-w-md mt-10">
    <input name='email' className ="border border-black text-black" type="email" />
    <input name='password' className ="border border-black text-black" type="password" />
    <button type="submit">Register</button>
  </form>
  )
}

到这里前端就差不多了,大家可以在http://localhost:3000/login 和http://localhost:3000/register看到你写的页面

nextAuth的官方文档:https://next-auth.js.org/providers/credentials在这里插入图片描述

基本就是用来nextAuth 官方文档中的credentials 字段,结尾加上export {handler as GET, handler as POST}; 就差不多了。

类似如下:

api/auth/[…nextauth]/route.ts

import NextAuth from "next-auth/next";
import CredentialsProvider from "next-auth/providers/credentials";
const handler =NextAuth({
  providers: [
    CredentialsProvider({

      credentials: {
        email: {  },
        password: { }
      },
      async authorize(credentials, req) {
        // Add logic here to look up the user from the credentials supplied
        const user = { id: "1", name: "J Smith", email: "jsmith@example.com" }
  
        if (user) {
          // Any object returned will be saved in `user` property of the JWT
          return user
        } else {
          // If you return null then an error will be displayed advising the user to check their details.
          return null
  
          // You can also Reject this callback with an Error thus the user will be sent to the error page with the error message as a query parameter
        }
      }
    })
  ]
})

export {handler as GET, handler as POST};

api/auth/register/route.ts

import { NextResponse } from "next/server";

export  async function POST(request : Request){

  try{

    const {email,password} = await request.json();
    console.log({email,password});
    
  }catch(e){
    console.log({e});
    
  }
  return NextResponse.json({message:"success"});
}

(1)register 页面

register\page.tsx

import { log } from "console";
import { FormEvent } from "react"

export default function LoginPage(){
  const handleSubmit= async (e:FormEvent<HTMLFormElement>)=>{
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    const response = await fetch(`/api/auth/register`,{
      method:"POST",
      body:JSON.stringify({
        email:formData.get('email'),
        password:formData.get('password'),
      }),
    })
    console.log({response});
    
  }
  return (
    <form onSubmit ={ handleSubmit}className="flex flex-col gap-2 mx-auto max-w-md mt-10">
    <input name='email' className ="border border-black text-black" type="email" />
    <input name='password' className ="border border-black text-black" type="password" />
    <button type="submit">register</button>
  </form>
  )
}

运行报错:
在这里插入图片描述

注:错误原因:需要把组件写到客户端部分,不能直接写进去Page.tsx

修改如下:

register/form.tsx

'use client'
import { FormEvent } from "react"

export default function Form(){
  const handleSubmit = async (e:FormEvent<HTMLFormElement>) =>{
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    console.log(formData.get('email'),formData.get('password'));
    const response = await fetch(`/api/auth/register`,{
      method:'POST',
      body:JSON.stringify({
        email:formData.get('email'),
        password:formData.get('password')
      }),
    });
    console.log({response});
  };
  
  return(
    <form onSubmit={handleSubmit} className="flex flex-col gap-2 mx-auto max-w-md mt-10">
      <input name='email' className ="border border-black text-black" type="email" />
      <input name='password' className ="border border-black text-black" type="password" />
      <button type="submit">Resgiter</button>
    </form>
  )
}

register/page.tsx

import Form from './form'

export default async function RegisterPage(){
  return <Form />;

}

到现在运行yarn dev 并到 http://localhost:3001/register 页面输入账户和密码,点击登录调用接口:fetch(/api/auth/register)然后打印{ email: ‘123@123’, password: ‘123’ }

在这里插入图片描述

到这里就完成简单的前后端编写,下面进入数据库交互部分。

四、数据库交互

1、数据库创建

在这里插入图片描述

依据需求创建表单users1 如上,一共有两个属性email 和password

2、vercel项目链接数据库并插入

确保Browse页面确实能查到这个新建的数据库在这里插入图片描述

(1)vercel postgre准备

yarn add @vercel/postgres

(2) 项目注册并写sql插入数据库

将API/auth/register/route.ts 的内容修改如下即可实现针对数据库的插入

import { NextResponse } from "next/server";
import {hash} from 'bcrypt'
import {sql} from '@vercel/postgres'
export  async function POST(request : Request){

  try{

    const {email,password} = await request.json();
    console.log({email,password});
    
    const hashedPassword = await hash(password,10); //将密码hash加密到10位

    const response = await sql`
    INSERT INTO users1 (email,password) 
    VALUES (${email},${password})
    `;
    //${参数} 参数化查询
  }catch(e){
    console.log({e});
    
  }
  return NextResponse.json({message:"success"});
}

前端页面register\form.tsx 如下,page.tsx 不变

'use client'
import { signIn } from "next-auth/react";
import { FormEvent } from "react"

export default function LoginForm() {
  const handleSubmit = async (e:FormEvent<HTMLFormElement>) =>{
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    signIn('credentials',{  //nextauth 登录模块
      email:formData.get('email'),
      password:formData.get('password'),
      redirect:false
    });
  };
  return(
    <form onSubmit={handleSubmit} className="flex flex-col gap-2 mx-auto max-w-md mt-10">
      <input name='email' className ="border border-black text-black" type="email" />
      <input name='password' className ="border border-black text-black" type="password" />
      <button type="submit">Login</button>
    </form>
  )
}

测试的时候可以发现可以显示登录信息了

问题:发现邮箱有时候同邮箱有多个,所以需要当相同的时候就不添加而是修改

在这里插入图片描述

在数据库中限制让email唯一

(3) 项目查询sql数据库并登录

将API/auth/[…nextauth]/route.ts 的内容修改如下即可实现针对数据库的插入

import { sql } from "@vercel/postgres";
import { compare } from "bcrypt";
import NextAuth from "next-auth/next";
import CredentialsProvider from "next-auth/providers/credentials";
const handler =NextAuth({
  session:{
    strategy:'jwt'
  },
  providers: [
    CredentialsProvider({

      credentials: {
        email: {  },
        password: { }
      },
      async authorize(credentials, req) {
       
        
        const response = await sql`
        SELECT * FROM users1 WHERE email=${credentials?.email}
        `;

        const user = response.rows[0];
        const passwordCorrect = await compare(
          credentials?.password ||'',
          user.password
        );
        const passworduser=user.password
        const passwordcre=credentials?.password
        console.log({passwordCorrect},{passwordcre},{passworduser});
        if (passwordCorrect){
          return {
            id:user.id,
            email:user.email
          }
        }
        //console.log({credentials}); //打印credentials信息
        return null
        
      }
    })
  ]
})

export {handler as GET, handler as POST};

前端页面login\form.tsx 如下,page.tsx 不变

'use client'
import { signIn } from "next-auth/react";
import { FormEvent } from "react"

export default function LoginForm() {
  const handleSubmit = async (e:FormEvent<HTMLFormElement>) =>{
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    const response= await signIn('credentials',{  //nextauth 登录模块
      email:formData.get('email'),
      password:formData.get('password'),
      redirect:false
    });
    console.log({response});
  };
  
  
  return(
    <form onSubmit={handleSubmit} className="flex flex-col gap-2 mx-auto max-w-md mt-10">
      <input name='email' className ="border border-black text-black" type="email" />
      <input name='password' className ="border border-black text-black" type="password" />
      <button type="submit">Login</button>
    </form>
  )
}

这时候就可以写入数据库了

五、状态增加

1、查询到登录之后登录自动跳转状态增加

解析:
如果查询到登录模块,没有返回error。则自动导航到‘/’目录同时刷新。
核心修改:

export default function LoginForm() {
  const router=useRouter();
  const handleSubmit = async (e:FormEvent<HTMLFormElement>) =>{
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    const response= await signIn('credentials',{  //nextauth 登录模块
      email:formData.get('email'),
      password:formData.get('password'),
      redirect:false
    });
    console.log({response});
    if(!response?.error){  //没有返回error
      router.push('/');    //跳转到‘/’
      router.refresh();    //刷新缓存
    }
  };

login/form.tsx全部内容如下

'use client'
import { signIn } from "next-auth/react";
import { useRouter } from "next/navigation";
import { FormEvent } from "react"

export default function LoginForm() {
  const router=useRouter();
  const handleSubmit = async (e:FormEvent<HTMLFormElement>) =>{
    e.preventDefault();
    const formData = new FormData(e.currentTarget);
    const response= await signIn('credentials',{  //nextauth 登录模块
      email:formData.get('email'),
      password:formData.get('password'),
      redirect:false
    });
    console.log({response});
    if(!response?.error){
      router.push('/');
      router.refresh();
    }
  };
  
  
  return(
    <form onSubmit={handleSubmit} className="flex flex-col gap-2 mx-auto max-w-md mt-10">
      <input name='email' className ="border border-black text-black" type="email" />
      <input name='password' className ="border border-black text-black" type="password" />
      <button type="submit">Login</button>
    </form>
  )
}

2、登出与登录状态转换

登录之后,登出
登出之后,登录,并自动跳转到首页
功能解析
在全部页面都需要有这个跳转。
1、在app首页的layout.tsx页面进行编写。
2、自动跳转用next

该功能核心修改是增加:

 <nav>
          {!!session &&
          <Logout />
          }
           {!session &&
          <Link href='/login'>Login</Link>
          }
        </nav>

文件全部代码如下:
layout.tsx

mport type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { getServerSession } from "next-auth";
import Link from "next/link";
import Logout from "./logout";

const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default async function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {

  const session = await getServerSession();
  return (
    <html lang="en">
      <body className={inter.className}>
        <nav>
          {!!session &&
          <Logout />
          }
           {!session &&
          <Link href='/login'>Login</Link>
          }
        </nav>
        
        {children}</body>
    </html>
  );
}

由于这个里面也涉及到后端,所以需要重新编写一个的客户端API进行处理,在同目录编写
logout.tsx

'use client'

import { signOut } from "next-auth/react"
export default function Logout(){
  return (
    <span onClick={() => {
      signOut();
    }}>
      Logout
    </span>
  )
}

到这里,登出与登录按钮增加完毕

3、重定向

当你登录后不想再返回登录页面可以参考以下的操作。
其他的网址也可以这么操作。

import { getServerSession } from "next-auth";
import Form from "./form";
import { redirect } from "next/navigation";


export default async function LoginPage(){
  const session =await getServerSession();
  if(session){
    redirect("/")
  }
  return <Form />
}

4、root保护

一些页面需要你登录之后才能访问,在这里面我们借助中间件实现这个操作
在项目主目前增加中间件
middleware.ts

export {default } from 'next-auth/middleware'

export const conifg ={matcher:['/dashboard']} //加入你要登录保护的地址

这样子,这个功能就实现完毕了。

5、root保护登录页面转为自定义登录页面

在nextauth 的route页面增加signin路径
pages:{
signIn:‘/login’,
},在这里插入图片描述

  • 13
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
你好!对于 json-server-auth使用,你可以按照以下步骤进行操作: 1. 首先,安装 json-server-auth 包。你可以使用 npm 进行安装,运行以下命令: ``` npm install json-server-auth ``` 2. 创建一个 JSON 数据文件,用于存储用户信息和受保护的资源。该文件可以是一个独立的 JSON 文件,也可以是一个包含 JSON 数据的 JavaScript 文件。 3. 在你的项目中创建一个新的 JSON Server 实例,并使用 json-server-auth 包装它。你可以在你的 JavaScript 代码中这样做: ```javascript const jsonServer = require('json-server'); const auth = require('json-server-auth'); const server = jsonServer.create(); const router = jsonServer.router('path/to/your/data.json'); const middlewares = jsonServer.defaults(); server.use(middlewares); server.db = router.db; server.use(auth); server.use(router); server.listen(3000, () => { console.log('JSON Server is running'); }); ``` 4. 运行你的服务器。在终端中执行以下命令: ``` node your-server-file.js ``` 5. 现在,你的 JSON Server 已经具备了基本的身份验证功能。你可以使用用户的用户名和密码进行身份验证,并限制对受保护资源的访问。 请注意,json-server-auth 提供了一些默认的身份验证和授权路由,你可以根据自己的需求进行自定义设置。你可以在 json-server-auth 的文档中找到更多的配置和用法示例。 希望这能对你有所帮助!如有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风吹落叶花飘荡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值