使用nextJs,apollo和cookie进行验证

时间:2020-11-03 15:07:54

标签: next.js apollo server-side-rendering react-apollo react-context

我的身份验证存在此问题,我不知道该如何解决...请帮助!

这是我的Login组件(来自模式组件):


const Login = () => {
  //Context
  const { state, setState } = useContext(AppContext);

  // Router
  const router = useRouter();

  // Mutations
  const [login, { data }] = useMutation(LOGIN);

  const handleMutation = () =>
    login({
      variables: { email: state.input.email, password: state.input.password },
    });

  // Effects
  useEffect(() => {
    if (data) {
      Cookies.set("JWT-TOKEN", data.login.accessToken);
      setState({
        ...state,
        isAuth: true,
        authModal: false, //close login modal
      });

      router.push("/account");
    }
  }, [data]);

  //CALLBACKS
  //email,pass
  const handleInput = (e, type) => {
    setState({ ...state, input: { ...state.input, [type]: e.target.value } });
  };

  return (
    <div>
      <Input onChange={(e) => handleInput(e, "email")} />
      <Input type="password" onChange={(e) => handleInput(e, "password")} />

      <Button onClick={handleMutation}>Login </Button>
    </div>
  );
};

这是一个简单的input,可以将emailpassword存储在全局上下文中(通过反应useContext

如果登录突变成功,则从'apollo'收到data时,我将后端签名的JWT令牌设置在cookie中,然后通过nextJs的router.push()重定向到/account页面。

这是全局上下文:

//context object
export const AppContext = createContext();

// provider component
export const AppProvider = ({ children }) => {
  const [state, setState] = useState({
    showDrawer: false,
    showCart: false,
    quickSearch: false,

    isAuth: Cookies.get("JWT-TOKEN") ? true : false,
    authModal: false, // toggle auth modal component
    emailToggle: false, //toggle emal auth component
    type: "Login", //Login / Sign Up / passReset / setNewPass
    input: { name: null, email: null, password: null, passwordConfirm: null },
    forgetSent: false, // message after `reset email` sent
  });

  return (
    <AppContext.Provider value={{ state, setState }}>
      {children}
    </AppContext.Provider>
  );
};

这是我的用户Account Page

import { useQuery } from "@apollo/client";
import { ME } from "graphql/Query";

const Account = () => {
  //Apolo
  const { data, loading, error } = useQuery(ME);
  const user = data?.me;

  // ERROR
  if (error) return <div>error: {error.message}</div>;

  // LOADING
  if (loading) return <p>Loading...</p>;

  return (
    <span>
      Welcome {user?.name} ({user?.email})
    </span>
  );
};

export default Account;

登录成功后,我被重定向到/account页,从error得到apollo,该查询请求是在没有cookie的情况下完成的。

  • 如果我通过console.log useEffect cookie,那么cookie就在那里。
  • 如果刷新页面,则查询成功。

所以问题一定在登录和重定向之间...

这也是我的apollo client

import { useMemo } from 'react'
import { ApolloClient, InMemoryCache } from '@apollo/client'
import Cookies from "js-cookie";

let apolloClient
const token = Cookies.get("XSRF-TOKEN");

 const enchancedFetch = (url, init) => {
    return fetch(url, {
      ...init,
      headers: {
        ...init.headers,
        ...(token ? { authorization: `Bearer ${token}` } : {}),
        // ...{ authorization: `Bearer ${token}` },
      },
    }).then((response) => response);
  };


function createIsomorphLink() {

    const { HttpLink } = require('@apollo/client/link/http')
    return new HttpLink({
      uri: process.env.NEXT_PUBLIC_GRAPHQL_API_ENDPOINT,
      credentials: 'same-origin',
      fetch:enchancedFetch
    })
  
}

function createApolloClient() {
  
  return new ApolloClient({
    ssrMode: typeof window === 'undefined',
    link: createIsomorphLink(),
    cache: new InMemoryCache(),
  })
}

export function initializeApollo(initialState = null) {
  const _apolloClient = apolloClient ?? createApolloClient()

  // If your page has Next.js data fetching methods that use Apollo Client, the initial state
  // gets hydrated here
  if (initialState) {
    _apolloClient.cache.restore(initialState)
  }
  // For SSG and SSR always create a new Apollo Client
  if (typeof window === 'undefined') return _apolloClient
  // Create the Apollo Client once in the client
  if (!apolloClient) apolloClient = _apolloClient

  return _apolloClient
}

export function useApollo(initialState) {
  const store = useMemo(() => initializeApollo(initialState), [initialState])
  return store
}

0 个答案:

没有答案