Nest.js与Next.js服务端Token处理及Session类工具咨询
Nest.js服务端Token处理及Next.js服务端组件Token管理方案
一、Nest.js侧的Token处理
1. 生成Token(以JWT为例)
Nest.js常用@nestjs/jwt包生成JWT令牌,用户登录验证通过后,签发包含用户核心信息的Token:
// auth.service.ts import { Injectable } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; @Injectable() export class AuthService { constructor(private jwtService: JwtService) {} async login(user: any) { const payload = { username: user.username, sub: user.id }; return { access_token: this.jwtService.sign(payload, { expiresIn: '15m' }), // 短时效访问令牌 refresh_token: this.jwtService.sign(payload, { expiresIn: '7d' }) // 长时效刷新令牌 }; } }
需要在模块里配置JWT密钥和默认选项(密钥别硬编码,从环境变量读取):
// auth.module.ts import { Module } from '@nestjs/common'; import { JwtModule } from '@nestjs/jwt'; import { AuthService } from './auth.service'; @Module({ imports: [ JwtModule.register({ secret: process.env.JWT_SECRET, signOptions: { expiresIn: '15m' }, }), ], providers: [AuthService], exports: [AuthService], }) export class AuthModule {}
2. 验证Token
用Passport的JWT守卫拦截未携带有效Token的请求,保护需要授权的接口:
// jwt-auth.guard.ts import { Injectable } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') {}
配置JWT策略,解析并验证Token的合法性:
// jwt.strategy.ts import { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor() { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), // 从请求头Authorization字段提取Token ignoreExpiration: false, secretOrKey: process.env.JWT_SECRET, }); } async validate(payload: any) { // 验证通过后,用户信息会挂载到req.user上供接口使用 return { userId: payload.sub, username: payload.username }; } }
在需要授权的接口上直接使用守卫:
// user.controller.ts import { Controller, Get, UseGuards, Request } from '@nestjs/common'; import { JwtAuthGuard } from './jwt-auth.guard'; @Controller('users') export class UserController { @Get('profile') @UseGuards(JwtAuthGuard) getProfile(@Request() req) { return req.user; } }
二、Next.js服务端组件的Token管理
针对你提到的服务端组件(export default async function Test() {})调用API的场景,没法用浏览器Cookie、也无类似PHP Session的工具,这里给你几种实用方案:
1. 单次请求内直接使用
如果只是当前组件调用API需要Token,直接获取后携带在请求头即可,无需持久化:
// app/test/page.tsx import axios from 'axios'; export default async function Test() { // 先调用登录接口获取Token const loginRes = await axios.post('http://你的NestAPI地址/auth/login', { username: '你的用户名', password: '你的密码' }); const { access_token } = loginRes.data; // 携带Token调用需要授权的接口 const profileRes = await axios.get('http://你的NestAPI地址/users/profile', { headers: { Authorization: `Bearer ${access_token}` } }); return <div>用户信息:{JSON.stringify(profileRes.data)}</div>; }
这种方式简单直接,Token仅在当前服务端请求周期内有效,用完即弃,适合一次性服务端请求场景。
2. 跨请求持久化存储(基于Redis)
如果需要在多个服务端请求之间共享Token,比如用户多次访问不同页面的服务端组件都要用到Token,可以用Redis存储:
// app/test/page.tsx import axios from 'axios'; import Redis from 'ioredis'; // 初始化Redis连接(建议抽成单独工具文件复用) const redis = new Redis({ host: process.env.REDIS_HOST, port: parseInt(process.env.REDIS_PORT || '6379'), }); export default async function Test({ params }: { params: { userId: string } }) { // 从Redis读取对应用户的Token let access_token = await redis.get(`user:${params.userId}:token`); if (!access_token) { // 未取到Token则重新登录获取 const loginRes = await axios.post('http://你的NestAPI地址/auth/login', { username: '你的用户名', password: '你的密码' }); access_token = loginRes.data.access_token; // 将Token存入Redis,过期时间和Token有效期保持一致(比如15分钟) await redis.set(`user:${params.userId}:token`, access_token, 'EX', 900); } // 携带Token调用接口 const profileRes = await axios.get('http://你的NestAPI地址/users/profile', { headers: { Authorization: `Bearer ${access_token}` } }); return <div>用户信息:{JSON.stringify(profileRes.data)}</div>; }
这种方式能实现跨请求的Token共享,适合需要维持用户登录状态的服务端场景。
3. 自动处理Token过期
Token过期后服务端会返回401错误,此时可以调用刷新Token接口获取新Token,再自动重试请求:
// app/test/page.tsx import axios from 'axios'; // 封装带Token自动刷新的请求函数 async function fetchWithRefresh(url: string, token: string, refreshToken: string) { try { return await axios.get(url, { headers: { Authorization: `Bearer ${token}` } }); } catch (error: any) { if (error.response?.status === 401) { // 调用刷新Token接口 const refreshRes = await axios.post('http://你的NestAPI地址/auth/refresh', { refresh_token: refreshToken }); const newToken = refreshRes.data.access_token; // 重试原请求 return await axios.get(url, { headers: { Authorization: `Bearer ${newToken}` } }); } throw error; } } export default async function Test() { const loginRes = await axios.post('http://你的NestAPI地址/auth/login', { username: '你的用户名', password: '你的密码' }); const { access_token, refresh_token } = loginRes.data; // 调用带自动刷新的请求 const profileRes = await fetchWithRefresh( 'http://你的NestAPI地址/users/profile', access_token, refresh_token ); return <div>用户信息:{JSON.stringify(profileRes.data)}</div>; }
内容的提问来源于stack exchange,提问作者Kenzo
相关产品推荐
相关产品推荐

