如何在TSOA接口中设置跨子域共享的认证Cookie?
问题描述
我基于Express搭建了后端服务,用TSOA定义接口。当前登录接口直接返回认证Token给前端存储,但现在有一个部署在同主域子域名下的第二个应用,需要共享这套认证体系,所以打算通过设置Cookie来实现Token的跨应用共享。
现有登录接口代码:
@Route('auth') @Tags('Auth') export class AuthController extends Controller { @SuccessResponse('200', 'Returns Token') @Post('/login') public async login(@Body() body: TokenRequest): Promise<TokenResponse> { // ... 登录逻辑实现 return token } }
我尝试注入Express的Response对象来设置Cookie,但无法成功获取;试过TSOA Controller基类的setHeader方法也没有效果,不知道正确的实现方式是什么。
解决方案
正确获取Express Response对象并设置跨子域Cookie
TSOA支持两种方式获取Express的Response实例,进而设置跨子域Cookie:
方式1:使用@Response()装饰器注入
确保从tsoa导入@Response()装饰器,同时将参数类型指定为Express的Response:
import { Controller, Route, Tags, Post, Body, SuccessResponse, Response } from 'tsoa'; import { Response as ExpressResponse } from 'express'; import { TokenRequest, TokenResponse } from './your-types-file'; @Route('auth') @Tags('Auth') export class AuthController extends Controller { @SuccessResponse('200', 'Returns Token') @Post('/login') public async login( @Body() body: TokenRequest, @Response() res: ExpressResponse ): Promise<TokenResponse> { // 执行登录逻辑,生成token和refreshToken const token = '生成的JWT Token'; const refreshToken = '生成的Refresh Token'; // 设置跨子域Cookie res.cookie('authToken', token, { domain: '.your-main-domain.com', // 主域名前加.,允许所有子域共享 path: '/', httpOnly: true, // 禁止前端JS访问,防范XSS secure: process.env.NODE_ENV === 'production', // 生产环境强制HTTPS sameSite: 'lax', // 根据业务需求选择strict/lax/none maxAge: 24 * 60 * 60 * 1000 // 有效期1天 }); res.cookie('refreshToken', refreshToken, { domain: '.your-main-domain.com', path: '/', httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 7 * 24 * 60 * 60 * 1000 // 有效期7天 }); return { token }; } }
方式2:使用TSOA Controller基类的response属性
TSOA的Controller基类已封装Express的Response实例,直接通过this.response访问即可:
import { Controller, Route, Tags, Post, Body, SuccessResponse } from 'tsoa'; import { TokenRequest, TokenResponse } from './your-types-file'; @Route('auth') @Tags('Auth') export class AuthController extends Controller { @SuccessResponse('200', 'Returns Token') @Post('/login') public async login(@Body() body: TokenRequest): Promise<TokenResponse> { // 执行登录逻辑,生成token和refreshToken const token = '生成的JWT Token'; const refreshToken = '生成的Refresh Token'; // 使用this.response设置Cookie this.response.cookie('authToken', token, { domain: '.your-main-domain.com', path: '/', httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 24 * 60 * 60 * 1000 }); this.response.cookie('refreshToken', refreshToken, { domain: '.your-main-domain.com', path: '/', httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'lax', maxAge: 7 * 24 * 60 * 60 * 1000 }); return { token }; } }
关键注意事项
- 启用cookie-parser中间件:在Express应用中添加
app.use(cookieParser()),否则res.cookie方法无法正常工作。 - 前端请求配置:子域名的前端应用发送请求时,需设置
withCredentials: true(Axios/Fetch均支持该配置),否则浏览器不会自动携带Cookie。 - 生产环境要求:
- 必须使用HTTPS,否则
secure: true的Cookie不会被浏览器保存; - 若需跨站点共享Cookie(
SameSite=None),必须同时设置secure: true。
- 必须使用HTTPS,否则
- Cookie参数说明:
domain:必须设置为主域(如.example.com),不能是具体子域,否则其他子域无法读取;httpOnly:建议开启,避免Token被前端JS窃取,降低XSS风险;sameSite:根据业务场景选择,lax是默认值,兼顾安全和可用性。
内容的提问来源于stack exchange,提问作者Haydn Morris
相关产品推荐
相关产品推荐

