简体   繁体   English

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

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

I am trying to pass res from my context into a resolver so that I can call context.res.cookie in my signin function and then send an http only cookie.我正在尝试将res从我的上下文传递到解析器,以便我可以在我的登录 function 中调用context.res.cookie ,然后发送一个 http only cookie。 I have the following code which I am not seeing the cookie added on the client but the sign in function is working besides that:我有以下代码,我没有在客户端上看到添加的 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,
      };
    },
  },
};

I have shortened the above code but originally I am returning the JWT token and mongodb user, I am trying to also add the http cookie of the same token (it will be a different token later when I sepearte access and refresh token).我已经缩短了上面的代码,但最初我返回的是 JWT 令牌和 mongodb 用户,我还尝试添加相同令牌的 http cookie(稍后当我单独访问和刷新令牌时它将是一个不同的令牌)。

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

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

The above code is just how I am passing the res, not sure if its needed but just in case.上面的代码就是我传递 res 的方式,不确定是否需要它,但以防万一。

The following is how the function will be called from the front end:以下是如何从前端调用 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="/" />
  }
  
};

So I needed to slightly change both my client and my server to solve my issue.所以我需要稍微改变我的客户端和服务器来解决我的问题。 On the client in apollo-client I needed to change my apolloClient from this:在 apollo-client 的客户端上,我需要将我的 apolloClient 更改为:

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

to this:对此:

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

Now on the server I needed to add cors like this:现在在服务器上我需要像这样添加 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 };
  },
});

Thus passing res to the resolver this way works perfectly fine.因此,以这种方式将 res 传递给解析器非常有效。 However when I was getting the cookie from server now it would get deleted if I refreshed the page thus I needed an explicit expiration date, thus I changed my cookie from:但是,当我现在从服务器获取 cookie 时,如果我刷新页面,它会被删除,因此我需要一个明确的到期日期,因此我将 cookie 更改为:

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

to (24 hour expiration):至(24 小时到期):

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

Some notes on this solution: On the client when you add the credentials: "include" , you NEED to also add the cors on the backend otherwise nothing will work, however if you remove both they will communicate fine just without cookies. Also if you add the cors and not the include nothing will break but you will not receive the cookies.关于此解决方案的一些注意事项:在客户端上,当您添加credentials: "include" ,您还需要在后端添加 cors,否则将无法正常工作,但是,如果您删除这两个凭据,它们将在没有 cookies 的情况下正常通信。另外,如果您添加 cors 而不是 include 什么都不会中断,但您不会收到 cookies。

Finally this post helped me find the solution, however I did not need to setup express middleware or use apollo-link-http library as you can see above in my solution, however the post may still be helpful.最后这篇文章帮助我找到了解决方案,但是我不需要设置 express 中间件或使用apollo-link-http库,正如您在我的解决方案中看到的那样,但是这篇文章可能仍然有帮助。

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

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