我最近刚刚从使用带有 apollo 服务器的 Express 切换到仅使用 apollo 服务器,因为订阅设置似乎更最新且更易于设置。我现在遇到的问题是我正在使用刷新令牌保存 cookie 以用于登录并在注销时清除 cookie。当我使用 Express 时,这有效。
const token = context.req.cookies[process.env.REFRESH_TOKEN_NAME!];
context.res.status(401);
自从从express/apollo切换到apollo服务器后,即使我在apollo服务器上公开req/res上下文,我也无法访问
req.cookies
。
我最终切换到这个(这是hacky)来获取cookie。
const header = context.req.headers.cookie
var cookies = header.split(/[;] */).reduce(function(result: any, pairStr: any) {
var arr = pairStr.split('=');
if (arr.length === 2) { result[arr[0]] = arr[1]; }
return result;
}, {});
这可行,但现在我不知道如何删除 cookie。我正在做的快递
context.res.clearCookie(process.env.REFRESH_TOKEN_NAME!);
由于 res.clearCookie 不存在,所以现在不知道如何清除 cookie。
只需将完全相同的 cookie 发送回客户端,并将
Expires
属性设置为过去的某个日期。请注意,cookie 其余部分的所有内容都必须完全相同,因此也请务必保留所有原始 cookie 属性。
而且,这里有一个关于此主题的 RFC 本身的链接:
最后,要删除 cookie,服务器会返回 Set-Cookie 标头 过期日期是过去的。 服务器就成功了 仅当 Path 和 Domain 属性位于 Set-Cookie 标头与 cookie 时使用的值相匹配 已创建。
至于如何做到这一点,如果您使用 Node 的
http
模块,您可以使用类似的东西(假设您有一个 response
来自传递给 http.createServer
的回调):
context.response.writeHead(200, {'Set-Cookie': '<Your Cookie Here>', 'Content-Type': 'text/plain'});
这是假设您的
context
可以访问它可以写入的 http response
。
您不必专门清除cookie。 expiresIn cookie 键可以为您完成此操作。这是我用来在 apollo-server-lambda 浏览器中设置 cookie 的代码片段。一旦 expiresIn 日期值超过当前日期时间,则 cookie 对于该主机/域将不再有效。您需要再次撤销用户的访问令牌或从应用程序中注销用户
import { ApolloServer, AuthenticationError } from "apollo-server-lambda";
import resolvers from "./src/graphql/resolvers";
import typeDefs from "./src/graphql/types";
const { initConnection } = require("./src/database/connection");
const {
validateAccessToken,
hasPublicEndpoint,
} = require("./src/bll/user-adapter");
const { addHoursToDate } = require("./src/helpers/utility");
const corsConfig = {
cors: {
origin: "http://localhost:3001",
credentials: true,
allowedHeaders: ["Content-Type", "Authorization"],
},
};
// creating the server
const server = new ApolloServer({
// passing types and resolvers to the server
typeDefs,
resolvers,
context: async ({ event, context, express }) => {
const cookies = event.headers.Cookie;
const accessToken = ("; " + cookies)
.split(`; accessToken=`)
.pop()
.split(";")[0];
const accessLevel = ("; " + cookies)
.split(`; accessLevel=`)
.pop()
.split(";")[0];
const expiresIn = ("; " + cookies)
.split(`; expiresIn=`)
.pop()
.split(";")[0];
const { req, res } = express;
const operationName = JSON.parse(event.body).operationName;
if (await hasPublicEndpoint(operationName)) {
console.info(operationName, " Is a public endpoint");
} else {
if (accessToken) {
const jwtToken = accessToken.split(" ")[1];
try {
const verifiedUser = await validateAccessToken(jwtToken);
console.log("verifiedUser", verifiedUser);
if (verifiedUser) {
return {
userId: verifiedUser,
};
} else {
console.log();
throw new AuthenticationError("Your token does not verify!");
}
} catch (err) {
console.log("error", err);
throw new AuthenticationError("Your token does not verify!");
}
}
}
return {
headers: event.headers,
functionName: context.functionName,
event,
context,
res,
};
},
cors: corsConfig,
formatResponse: (response, requestContext) => {
if (response.data?.authenticateUser || response.data?.revokeAccessToken) {
// console.log(requestContext.context);
const { access_token, user_type, access_token_generated_on, email } =
response.data.authenticateUser || response.data.revokeAccessToken;
const expiresIn = addHoursToDate(new Date(access_token_generated_on), 12);
requestContext.context.res.set("set-cookie", [
`accessToken=Bearer ${access_token}`,
`accessLevel=${user_type}`,
`expiresIn=${new Date(access_token_generated_on)}`,
`erUser=${email}`,
]);
}
if (response.data?.logoutUser) {
console.log("Logging out user");
}
return response;
},
});