我跟着Ben Awad's 13-hour Fullstack React GraphQL TypeScript Tutorial走,在设置登录cookie时遇到了一堵墙(aprx在1:50:00)。
我想我成功地连接到了redis,设置了express-session并设置了请求类型,但是在graphql沙箱中,我在Inspect->Application中看不到我的cookie (名为'qid')。
index.ts
import { MikroORM } from "@mikro-orm/core";
import { __prod__ } from "./constants";
import microConfig from "./mikro-orm.config";
import express from "express";
import { ApolloServer } from "apollo-server-express";
import { buildSchema } from "type-graphql";
import { HelloResolver } from "./resolvers/hello";
import { PostResolver } from "./resolvers/post";
import { UserResolver } from "./resolvers/user";
import redis from "redis";
import session from "express-session";
import connectRedis from "connect-redis";
const main = async () => {
const orm = await MikroORM.init(microConfig);
await orm.getMigrator().up();
const app = express();
const RedisStore = connectRedis(session);
const redisClient = redis.createClient();
app.use(
session({
name: "qid",
store: new RedisStore({
client: redisClient,
disableTouch: true,
}),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 10,
httpOnly: true,
sameSite: "none",
// secure: __prod__,
},
saveUninitialized: false,
secret: "dfhfdjkgfkbjktzkzf",
resave: false,
})
);
app.use(function (req, res, next) {
res.header(
"Access-Control-Allow-Origin",
"https://studio.apollographql.com"
);
res.header("Access-Control-Allow-Credentials", "true");
next();
});
const apolloServer = new ApolloServer({
schema: await buildSchema({
resolvers: [HelloResolver, PostResolver, UserResolver],
validate: false,
}),
context: ({ req, res }) => ({ em: orm.em, req, res }),
});
await apolloServer.start();
apolloServer.applyMiddleware({
app,
cors: {
credentials: true,
origin: new RegExp("/*/"),
},
});
app.listen(4000, () => {
console.log("server started on port 4000");
});
};
main();
types.ts
import { EntityManager, IDatabaseDriver, Connection } from "@mikro-orm/core";
import { Request, Response } from "express";
import { Session, SessionData } from "express-session";
export type MyContext = {
em: EntityManager<any> & EntityManager<IDatabaseDriver<Connection>>;
req: Request & {
session: Session & Partial<SessionData> & { userId: number };
};
res: Response;
};
和我的userResolver (user.ts)
import { User } from "../entities/User";
import { MyContext } from "../types";
import {
Arg,
Ctx,
Field,
InputType,
Mutation,
ObjectType,
Query,
Resolver,
} from "type-graphql";
import argon2 from "argon2";
@InputType()
class UsernamePasswordInput {
@Field()
username: string;
@Field()
password: string;
}
@ObjectType()
class FieldError {
@Field()
field: string;
@Field()
message: string;
}
@ObjectType()
class UserResponse {
@Field(() => [FieldError], { nullable: true })
errors?: FieldError[];
@Field(() => User, { nullable: true })
user?: User;
}
@Resolver()
export class UserResolver {
@Mutation(() => UserResponse)
async login(
@Arg("options", () => UsernamePasswordInput) options: UsernamePasswordInput,
@Ctx() { em, req }: MyContext
): Promise<UserResponse> {
const user = await em.findOne(User, { username: options.username });
if (!user) {
return {
errors: [
{
field: "username",
message: "username does not exist",
},
],
};
}
const valid = await argon2.verify(user.password, options.password);
if (!valid) {
return {
errors: [
{
field: "password",
message: "incorrect password",
},
],
};
}
req.session.userId = user.id;
return {
user,
};
}
}
我试着按照graphql沙箱的要求设置res.headers,但仍然没有效果。非常感谢您的帮助,谢谢!
发布于 2021-09-26 02:36:55
好吧,我不确定发生了什么,但我似乎解决了这个问题。
我的想法是:阿波罗游乐场退役了,localhost:port/graphql现在重定向到GraphQL GraphQL沙盒到不同的url,我猜cookie不会被传输到这个位置,但cookie被设置在本地主机。
因此,有一种方法可以强制Apollo仍然使用游乐场,方法是添加:
import { ApolloServerPluginLandingPageGraphQLPlayground } from "apollo-server-core";
const apolloServer = new ApolloServer({
...,
plugins: [
ApolloServerPluginLandingPageGraphQLPlayground({
// options
}),
],
});
这样,Playground就会出现,你可以设置
"request.credentials": "include",
在设置中,cookie显示在localhost:port。
我希望这能帮助任何人解决这个问题--但是我仍然不确定这是不是一个正确的解决方案。
发布于 2022-01-11 12:33:03
添加旧的游乐场作为插件可能会起作用,但是,因为他们说它正在被弃用,如果你想让它在新的Apollo Studio中工作,以下是我如何做到的:
我在初始化应用程序后添加了这三行:
app.set("trust proxy", !process.env.NODE_ENV === "production");
app.set("Access-Control-Allow-Origin", "https://studio.apollographql.com");
app.set("Access-Control-Allow-Credentials", true);
下面是我的会话的配置:
const RedisStore = connectRedis(session);
const redisClient = redis.createClient();
app.use(
session({
saveUninitialized: false,
store: new RedisStore({ client: redisClient }),
cookie: {
maxAge: 1000 * 60 * 60 * 24 * 365 * 1, // 1 year
httpOnly: true,
sameSite: "none",
secure: true, // if true, studio works, postman doesn't; if false its the other way around
},
name: "qid",
secret: "keyboard cat",
resave: false,
}),
);
然后,转到Apollo Studio,转到连接设置->编辑Cookie包含Cookie(这真的很难找到):
确保在每次登录请求时都发送此标头:x-forwarded-proto: https
https://stackoverflow.com/questions/69333408
复制相似问题