Next.js 14 踩坑:处理API中的JWT登录认证问题

前言

在使用 Next.js14 开发登录登出功能时遇到一个问题:可以设置 cookie,但无法清除 cookie。

在开发这个功能时,借助了 Route Handler 的特性,关于 cookie 的处理,官网提到了 next/headers 的 cookies API;同样可以通过 Request、Response 和 NextRequest、NextResponse 提供的相关方法处理。NextRequest、NextResponse 来自 next/server,它们分别拓展了 Web Request APIWeb Response API 的功能。

登录功能

我的 JWT 来自 API 接口,因此做了一些 BFF 的工作,下面是登录功能的实现:

ts 复制代码
// app/api/login/route.ts
import { api } from '@/config/api';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(request: NextRequest) {
  const body = await request.json();
  const { email, password } = body;

  const response = await fetch(`${api}/login`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      email,
      password,
    }),
  });

  if (response.status === 404) {
    return NextResponse.json({
      success: false,
      msg: '请求地址不存在',
    });
  }

  const json = await response.json(); // 解析出失败的 json 数据
  if (!response.ok) {
    return NextResponse.json(
      {
        success: false,
        msg: json.message,
      },
      { status: response.status || 500 }
    );
  }
  const token = json.data.token;

  return NextResponse.json(
    // 返回body内容
    {
      success: true,
      msg: json.message,
    },
    // 设置其他
    {
      headers: {
        'Set-Cookie': `token=${token};path=/;max-age=86400;HttpOnly`,
      },
    }
  );
}

调用 NextResponse.json 方法,第一个参数为返回给前端 json 数据,第二个参数用来配置请求头、状态码。在服务端设置响应头 Set-Cookie 后,发送给客户端,以后客户端就会自动带上请求头 Cookie。在上面代码中,Set-Cookie 中最重要的参数就是 token,它的值来自 API 中返回的 jwt 字符串。

  1. 登录时,响应头中加入了 Set-Cookie:
  1. Cookie 中存入了 token:
  1. 发请求时,请求头中存在 Cookie:

登出功能

登出时,需要把 cookie 删除,于是我使用了 NextRequest 和 NextResponse 中提供的 request.cookie.delete方法和 response.cookie.delete 方法:

ts 复制代码
request.cookies.delete('token');

let response = NextResponse.next();
response.cookies.delete('token');

但这并不起作用。

下面是有效的代码:

ts 复制代码
import { NextResponse } from 'next/server';
import { cookies } from 'next/headers';

export async function DELETE() {
  // 设置过期时间为0来删除cookie
  cookies().set('token', '', { maxAge: 0 });

  return NextResponse.json({
    success: true,
    msg: '登出成功',
  });
}

调用 next/headers 中的 cookies 成功地删除了 cookies,实现了登出功能。

路由中间件

在 Next.js 中的中间件是介于服务器和应用之间的一层介质。当一个请求到达应用时,它会首先通过中间件。然后中间件可以根据这个请求的信息(比如URL、headers、cookies等)执行一些动作,然后有选择的转发这个请求到你的页面或者api路由,或者直接返回一个响应。

有了中间件,你就可以在一个集中的地方处理跨越多个页面或API路由的逻辑。比如:

  • 认证和授权:检查请求的 cookie 或 header,来确认用户的身份,然后决定他是否有权限访问请求的资源。
  • 重定向和路由改写
  • 自定义的缓存规则

下面是检查认证和重定向的例子:

ts 复制代码
import { NextRequest, NextResponse } from 'next/server';

export function middleware(request: NextRequest) {
  // 检查 token(从cookie中获取token)
  const token = request.cookies.get('token')?.value;

  // 没有 token 时,跳回登录页
  if (!token) {
    const url = request.nextUrl.clone();
    url.pathname = '/login';
    return NextResponse.redirect(url);
  }
}

如果未登录,则重定向到登录页。

为什么使用 cookie?

要清楚 Route Handler 属于服务器层面,这里无法使用浏览器提供的window对象,也就无法使用HTML5的 localStorage 和 sessionStorage 作为 token 的存储方案。路由中间件 middleware.ts 也在服务器中,同样无法调用浏览器中的 localStorage 等 API。

综上,在客户端和服务端都能够使用的存储方案只有 cookie。


技术交流:

公众号:见嘉 Being Dev

v:with_his_x

相关推荐
耶啵奶膘1 小时前
uniapp-是否删除
linux·前端·uni-app
NiNg_1_2342 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
王哈哈^_^3 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
Chrikk3 小时前
Go-性能调优实战案例
开发语言·后端·golang
幼儿园老大*3 小时前
Go的环境搭建以及GoLand安装教程
开发语言·经验分享·后端·golang·go
canyuemanyue3 小时前
go语言连续监控事件并回调处理
开发语言·后端·golang
杜杜的man3 小时前
【go从零单排】go语言中的指针
开发语言·后端·golang
cs_dn_Jie3 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic4 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿4 小时前
webWorker基本用法
前端·javascript·vue.js