axios:如何在成功授权后准确保留 session 并随后续请求一起发送 - 在没有浏览器的情况下进行测试

axios : How exactly to preserve session after successful authorization and send with subsequent request - while testing without browser

在这个测试用例中,我发送一个带有用户名和密码的 axios post 请求到本地的 ExpressJS 服务器 运行 passportjs。服务器以状态代码 200 响应,并使用 set-cookie.

发送适当的 header

我需要将后续请求视为授权请求,因为尝试了以下选项,但 none 似乎有效。它被拒绝,状态代码为 401。

第一次使用用户名和密码调用,响应状态为 200

const userDoc = {
    userId: 'test-user-1',
    userName: 'Test User 1',
    emailId: 'test.user.1@abc.xom',
    password: 'test-password'
} ;

let resp

resp = await axios({method : 'post', url : 'http://localhost:4040/auth/local', data : {userId: userDoc.userId, password: userDoc.password },withCredentials: true   })

以下选项用于发送下一个请求

  1. 发送作为第一个请求的一部分收到的 cookie

     const headers = { headers : {Cookie: resp.headers['set-cookie'][0] } };
    
  2. 发送 header 作为第一个请求的一部分收到的

     const headers = { headers : resp.headers};
    
  3. 发送 withCredentials: true 连同上面的 headers.

使用上述任一选项进行第二次调用

resp = await axios({method : 'post', url : 'http://localhost:4040/v1/master/account', data : accountDoc , headers, withCredentials: true})
  1. 使用httpAgent,keepAlive与axios实例
const axios = require('axios')
const http = require("http")
const httpAgent = new http.Agent({keepAlive : true , timeout :1000})
const instance = axios.create({httpAgent})

const resp1 = await instance({method : 'post', url : 'http://localhost:4040/auth/local', data : {userId: userDoc.userId, password: userDoc.password, } , withCredentials: true })

const resp2 = await instance({method : 'post', url : 'http://localhost:4040/v1/master/account', data : accountDoc , withCredentials: true })

已拒绝,状态代码为 401

--   Error: Request failed with status code 401
at createError (/home/Projects/FinAccounts2003/node_modules/axios/lib/core/createError.js:16:15)
at settle (/home/Projects/FinAccounts2003/node_modules/axios/lib/core/settle.js:17:12)
at IncomingMessage.handleStreamEnd (/home/Projects/FinAccounts2003/node_modules/axios/lib/adapters/http.js:269:11)
at IncomingMessage.emit (events.js:412:35)
at endReadableNT (internal/streams/readable.js:1334:12)
at processTicksAndRejections (internal/process/task_queues.js:82:21)

服务器代码是标准的passport-js本地代码,与浏览器兼容。

可能有些问题是重复的,给出的解决方案是1) withCredentials: true,上面已经试过了2) Authorization: Bearer ${token} - 这种情况不适用,在passport js中,cookie是直接已设置,但未获取令牌。

对我有用的一个解决方案是使用模块 tough-cookie and axios-cookiejar-support。我将它们组合在一个 persistent-client.js 文件中,然后我能够在请求之间保持会话(commonJS):

const axios = require('axios').default;
const { CookieJar } = require('tough-cookie');
const { wrapper } = require('axios-cookiejar-support');

module.exports = function () {
    const jar = new CookieJar();

    const client = wrapper(axios.create({ jar }));

    return client;
}

我认为您不应该为此使用任何第三方包,尤其是如果他们使用 javascript 直接访问 cookie(这是一个 XSS 安全漏洞)。应使用 securehttp-only 设置 Cookie,切勿直接使用 Document.cookie 访问。

  • 确保 passport 确实设置了您的 cookie,并且您在登录时正确发回了 cookie。验证它是否已在您的浏览器中设置。

  • 确保您在 express 中启用了 CORS,您已经指定了您从中发出请求的域,并且您已经在 CORS 中启用了凭据。

  • 确保您在 axios 请求中使用 withCredentials

  • 确保您已使用正确的域和路径设置 cookie。

有两种不同的方法可以将 session 授权令牌从服务器发送到客户端(网络浏览器)

  1. 通过 (HttpOnly) 响应 headers.
  2. 通过响应 body。

并且有两种不同的方法来授权客户端请求(将 session 令牌从网络浏览器发送到服务器。)

一个。自动:HttpOnly headers

乙。手动:Authorization: Bearer [TOKEN]

通常方法一和方法A一起使用,方法二和方法B一起使用,我觉得你搞混了。

如果服务器使用 Set-Cookie 发送 session 令牌,那么我认为浏览器会自动在所有未来请求(到同一域)中自动发送 session 令牌.

您能确认服务器上 set-cookie header 的实际内容是什么吗?请注意,如果这些是 HttpOnly cookie,您可能无法通过 JS 检查;检查开发控制台的“网络”选项卡。您还可以检查是否从“应用程序”选项卡设置了任何新的 cookie。

如果客户端确实需要通过 headers 手动发送令牌,则 header 需要符合特定的 Authorization cookie 格式。 (您没有这样做。您只是在回显从服务器收到的 headers。)

查看我的response to a similar question