You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Expo Web项目中passport-spotify的session内accessToken为undefined问题

问题分析与解决方案

你遇到的核心问题是:Spotify认证回调中能正常获取并存储accessToken到session,但后续请求其他路由时,req.session.accessToken和req.user.accessToken均为undefined,这通常是Passport会话序列化缺失、跨域cookie配置错误或前端未携带凭证导致的。

1. 补充Passport序列化/反序列化函数

Passport依赖serializeUser和deserializeUser维持会话中的用户数据,你的代码缺少这两个函数,导致后续请求无法恢复req.user,也无法正确持久化session中的用户信息。

添加以下代码到Passport配置后:

// 序列化用户对象到session
passport.serializeUser((user, done) => {
  // 只存储必要字段,包括accessToken
  done(null, { id: user.id, accessToken: user.accessToken });
});

// 从session反序列化用户对象到req.user
passport.deserializeUser((userObj, done) => {
  done(null, userObj);
});

后续请求中,req.user会包含你在verify回调中附加的accessToken,无需手动操作req.session.accessToken。

2. 修复跨域Session Cookie配置

你的后端运行在localhost:5001,前端在localhost:8081,属于跨域场景,默认情况下浏览器不会携带session cookie到后端,需要调整CORS和session配置:

步骤1:配置CORS允许凭证

先安装并引入cors中间件:

const cors = require('cors');

app.use(cors({
  origin: 'http://localhost:8081', // 允许前端域名
  credentials: true // 允许携带cookie
}));

步骤2:调整Session的Cookie参数

修改session配置,确保跨域下cookie能被正确携带:

app.use(
  session({
    secret: "x",
    resave: false,
    saveUninitialized: false,
    cookie: {
      sameSite: 'none', // 跨域场景必须设置为none
      secure: process.env.NODE_ENV === 'production', // 生产环境设为true(HTTPS),本地开发可设为false
      httpOnly: true,
      maxAge: 3600000 // 和Spotify accessToken过期时间匹配(默认1小时)
    }
  })
);

3. 前端请求必须携带凭证

前端调用后端接口时,需要明确告知浏览器携带cookie:

  • 使用fetch时:
fetch('http://localhost:5001/spotify/get-currently-playing', {
  credentials: 'include'
})
.then(res => res.json())
.then(data => console.log(data));
  • 使用axios时:
axios.get('http://localhost:5001/spotify/get-currently-playing', {
  withCredentials: true
});

4. 验证会话一致性

可以在回调和目标路由中打印sessionID,确认前后请求的会话是否一致:

// 认证回调中
console.log("回调会话ID:", req.sessionID);

// /spotify/get-currently-playing路由中
console.log("播放接口会话ID:", req.sessionID);

如果两个ID不一致,说明cookie未被携带,需检查跨域配置和前端请求设置。

优化后的路由示例

补充序列化函数后,你可以直接通过req.user.accessToken获取令牌,无需手动操作session:

app.get("/spotify/get-currently-playing", async (req, res) => {
  try {
    if (!req.user?.accessToken) {
      throw new Error("未找到访问令牌");
    }
    const userData = await getCurrentSongInfo(req.user.accessToken);
    res.json(userData);
  } catch (err) {
    res.status(401).json({ error: err.message });
  }
});

内容的提问来源于stack exchange,提问作者Ddefin Orsstt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:27:41