繁体   English   中英

设置 http 仅来自 apollo graphql 解析器的 cookie

[英]Set http only cookie from resolver in apollo graphql

我正在尝试将res从我的上下文传递到解析器,以便我可以在我的登录 function 中调用context.res.cookie ,然后发送一个 http only cookie。 我有以下代码,我没有在客户端上看到添加的 cookie,但 function 中的登录除此之外还在工作:

const resolvers = {
  Mutation: {
    signin: async (_, { email, password }, context) => {
     const user = await User.findOne({ email: email });
     if (!user) {
       throw new Error("No such user found");
     }
     const valid = bcrypt.compare(password, user.password);
     if (!valid) {
       throw new Error("Invalid password");
     }
     const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, 
     {
     expiresIn: "30m",
     });
      
      context.res.cookie("token", token, {
        httpOnly: true,
        secure: true,
        maxAge: 8600,
      });

      return {
        token,
        user,
      };
    },
  },
};

我已经缩短了上面的代码,但最初我返回的是 JWT 令牌和 mongodb 用户,我还尝试添加相同令牌的 http cookie(稍后当我单独访问和刷新令牌时它将是一个不同的令牌)。

const server = new ApolloServer({
  typeDefs,
  resolvers,
  context: async ({ req, res }) => {
    /* Authentication boiler plate */

    return { isAuthenticated, res };
  },
});

上面的代码就是我传递 res 的方式,不确定是否需要它,但以防万一。

以下是如何从前端调用 function:

export const Login = () => {
  const SIGN_IN = gql`
    mutation Signin($email: String!, $password: String!) {
      signin(email: $email, password: $password) {
        token
        user {
          id
          name
          email
        }
      }
    }
  `;

  const [signIn, { error, loading, data }] = useMutation(SIGN_IN);

  const signInFunction = async () => {
    signIn({
      variables: {
        email: email,
        password: password,
      },
    });
  };

  if (data) {
   return <Navigate to="/" />
  }
  
};

所以我需要稍微改变我的客户端和服务器来解决我的问题。 在 apollo-client 的客户端上,我需要将我的 apolloClient 更改为:

const apolloClient = new ApolloClient({
  uri: "http://localhost:3001/graphql",
  cache: new InMemoryCache(),
});

对此:

const apolloClient = new ApolloClient({
  uri: "http://localhost:3001/graphql",
  cache: new InMemoryCache(),
  credentials: "include",
});

现在在服务器上我需要像这样添加 cors:

const server = new ApolloServer({
  typeDefs,
  resolvers,
  cors: {
    origin: "http://localhost:3000",
    credentials: true,
  },
  context: async ({ req, res }) => {
    /* insert any boilerplate context code here */
    return { isAuthenticated, res };
  },
});

因此,以这种方式将 res 传递给解析器非常有效。 但是,当我现在从服务器获取 cookie 时,如果我刷新页面,它会被删除,因此我需要一个明确的到期日期,因此我将 cookie 更改为:

context.res.cookie("token", token, {
        httpOnly: true,
        secure: true,
        maxAge: 8600,
      });

至(24 小时到期):

context.res.cookie("token", token, {
        httpOnly: true,
        secure: true,
        expires: new Date(Date.now() + 24 * 60 * 60 * 1000),
      });

关于此解决方案的一些注意事项:在客户端上,当您添加credentials: "include" ,您还需要在后端添加 cors,否则将无法正常工作,但是,如果您删除这两个凭据,它们将在没有 cookies 的情况下正常通信。另外,如果您添加 cors 而不是 include 什么都不会中断,但您不会收到 cookies。

最后这篇文章帮助我找到了解决方案,但是我不需要设置 express 中间件或使用apollo-link-http库,正如您在我的解决方案中看到的那样,但是这篇文章可能仍然有帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM