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

Ionic 4向Express路由传Token遇阻,无法验证Storage中Token状态

问题分析与解决方案

你遇到的res.user.access_token显示undefined的问题,核心原因是后端返回的user是一个数组,而你在前端把它当成了单个对象来访问。

看你提供的console.log结果:

res.user:[{"id":1,"name":"Admin","email":"Admin@test.com","password":"$2a$10$2OaS5CyGKMSF5J8wed5W7.qyNFYrPScBM49SgU7L9MBMVF0RWxx1e","created_at":"2019-10-16T13:28:06.000Z","access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiaWF0IjoxNTcyNDU1MTk3LCJleHAiOjE1NzI1NDE1OTd9.2eFbQ294TG6gvKUxSyaQGDBEas7ZLFT8k9H7jnpOoXQ"}]

明显res.user是一个包含单个用户对象的数组,直接访问res.user.access_token自然会得到undefined——数组没有这个属性,正确的访问方式应该是res.user[0].access_token。

修复方案

方案1:修改后端代码(推荐)

因为登录逻辑是查找单个用户,后端应该返回单个用户对象而非数组。调整Express路由的返回部分:

router.post('/login', (req, res) => { 
  const email = req.body.email; 
  const form_password = req.body.password; 
  findUserByEmail(email, (err, user) => { 
    if (err) return res.status(500).send({ "message": 'Server error!', "status": '500' }); 
    if (!user[0]) return res.status(404).send({ "message": 'User not found!', "status": '404' }); 
    const result = bcrypt.compareSync(form_password, user[0].password); 
    if (!result) return res.status(401).send({ "message": 'Password not valid!', "status": '401' }); 
    const expiresIn = 24 * 60 * 60; 
    user[0].access_token = jwt.sign({ id: user[0].id }, process.env.SECRET_KEY, { expiresIn: expiresIn }); 
    // 把返回的user改成user[0],返回单个对象
    res.status(200).send({ 
      "user": user[0], 
      "expires_in": expiresIn, 
      "message": 'Success!', 
      "status": '200' 
    }); 
  }); 
});

这样前端拿到的res.user就是单个对象,原来的res.user.access_token就能正常获取值了。

方案2:修改前端代码

如果暂时不想改动后端,可以调整前端访问路径:

login(user: User): Observable<AuthResponse> { 
  return this.httpClient.post(`${this.AUTH_SERVER_ADDRESS}/login`, user).pipe( 
    tap(async (res: AuthResponse) => { 
      // 先判断数组是否有内容
      if (res.user && res.user.length > 0) { 
        const userData = res.user[0];
        console.log("res.user.access_token:" + userData.access_token); 
        await this.storage.set("ACCESS_TOKEN", userData.access_token); 
        // 注意expires_in是在响应根层级,不是user数组里的
        await this.storage.set("EXPIRES_IN", res.expires_in); 
        this.authenticationState.next(true); 
      } 
    }) 
  ) 
}

验证Token是否存入Storage的方法

方法1:在代码中主动验证存储结果

在存储操作完成后,立即调用storage.get获取值并打印:

tap(async (res: AuthResponse) => { 
  if (res.user && res.user.length > 0) { 
    const userData = res.user[0];
    await this.storage.set("ACCESS_TOKEN", userData.access_token); 
    await this.storage.set("EXPIRES_IN", res.expires_in); 

    // 验证存储内容
    const savedToken = await this.storage.get("ACCESS_TOKEN");
    const savedExpires = await this.storage.get("EXPIRES_IN");
    console.log("已存储的Token:", savedToken);
    console.log("已存储的过期时间:", savedExpires);

    this.authenticationState.next(true); 
  } 
})

方法2:通过浏览器开发者工具查看

如果使用的是Ionic的Storage,默认会存在localStorage(或IndexedDB)中:

  1. 打开浏览器开发者工具(快捷键F12)
  2. 切换到Application标签页
  3. 在左侧菜单找到Local Storage(或Indexed DB),展开后查看对应键值对,确认ACCESS_TOKEN和EXPIRES_IN是否存在且值正确。

方法3:在其他组件中检查存储状态

在需要验证登录状态的组件中,注入AuthenticationService并查询存储:

constructor(private authService: AuthenticationService) {}

ngOnInit() {
  this.authService.storage.get("ACCESS_TOKEN").then(token => {
    console.log("从Storage获取的Token:", token);
    if (token) {
      console.log("Token已成功存入");
    } else {
      console.log("Token未存入");
    }
  });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:28:00