NextJS中JWT认证遇难题:边缘运行时无法读取公钥求方案
解决Next.js中间件中RS256 JWT验证的公钥读取问题
不用单独搭建Express应用,Next.js本身就能解决这个问题,以下是几个可行的方案:
方案一:将公钥嵌入环境变量
RS256的公钥是PEM格式的文本,可以直接将其转成单行格式(把换行符替换为\n)后存入环境变量,中间件直接调用即可。
操作步骤:
- 打开你的公钥文件,复制全部内容,把换行符替换为
\n,比如将:
-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA... ... -----END PUBLIC KEY-----
转换为:"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...\n...\n-----END PUBLIC KEY-----"
- 将转换后的值存入
.env.local的JWT_PUBLIC_KEY变量中 - 中间件中直接使用(推荐用
jose库,它适配边缘运行时,无需Node.js的fs模块):
import { jwtVerify } from 'jose'; import { NextResponse } from 'next/server'; export async function middleware(request) { const token = request.cookies.get('token')?.value; if (!token) return NextResponse.redirect(new URL('/login', request.url)); const publicKey = new TextEncoder().encode(process.env.JWT_PUBLIC_KEY); try { await jwtVerify(token, publicKey, { algorithms: ['RS256'] }); return NextResponse.next(); } catch (err) { return NextResponse.redirect(new URL('/login', request.url)); } }
方案二:构建时嵌入公钥到代码
利用Next.js的构建时能力,提前读取公钥并生成一个常量文件,中间件直接导入该文件即可。
操作步骤:
- 新建脚本文件
scripts/generate-public-key.js:
const fs = require('fs'); const path = require('path'); const publicKey = fs.readFileSync(path.join(__dirname, '../public-key.pem'), 'utf8'); fs.writeFileSync(path.join(__dirname, '../app/public-key.js'), `export const PUBLIC_KEY = \`${publicKey}\`;`);
- 修改
package.json的构建命令,在构建前执行该脚本:
"scripts": { "prebuild": "node scripts/generate-public-key.js", "build": "next build", "dev": "next dev" }
- 中间件中导入使用:
import { PUBLIC_KEY } from './public-key'; import { jwtVerify } from 'jose'; import { NextResponse } from 'next/server'; export async function middleware(request) { const token = request.cookies.get('token')?.value; if (!token) return NextResponse.redirect(new URL('/login', request.url)); const publicKey = new TextEncoder().encode(PUBLIC_KEY); try { await jwtVerify(token, publicKey, { algorithms: ['RS256'] }); return NextResponse.next(); } catch (err) { return NextResponse.redirect(new URL('/login', request.url)); } }
这个方案避免了公钥暴露在环境变量中,构建时直接将公钥嵌入代码,边缘运行时可直接读取。
方案三:改用HS256对称加密(业务场景允许时)
如果你的业务不需要非对称加密的特性(比如无需区分签名和验证的密钥权限),可以直接切换到HS256算法。将密钥存入环境变量,验证时直接使用该密钥即可,这种方式最简便,完全适配边缘运行时。
注意:HS256的密钥需要严格保密,因为签名和验证使用同一个密钥,一旦泄露就可能被伪造令牌。
为什么不需要单独搭建Express?
Next.js的API路由本身就能处理JWT生成逻辑,中间件负责请求拦截和验证,整套流程可以在Next.js内部完成,额外搭建Express只会增加系统复杂度,没有必要。
内容的提问来源于stack exchange,提问作者Some Guy
相关产品推荐
相关产品推荐

