Как обновить контекст после аутентификации пользователя - PullRequest
1 голос
/ 06 июня 2019

Я боролся с проблемой аутентификации в течение нескольких часов.Я успешно вхожу в систему из интерфейса React, но не могу обновить заголовки токеном в контексте.После входа в систему мне нужно обновить страницу, чтобы успешно запросить зарегистрированного пользователя.Функция setContext запускается до того, как функция входа в систему обновляет токен в localStorage.

Я попытался также выполнить запрос с client.query({ query: LOGGED_USER }) в хуке useEffect, но результат тот же.Мне всегда нужно обновить страницу до того, как LOGGED_USER вернет что-то отличное от null.


INDEX.JS
const httpLink = createHttpLink({
  uri: 'http://localhost:4000/graphql'
})

const authLink = setContext((_, { headers }) => {

  // After login this function is run. The problem is that at that point
  // there is still token in the local storage and therefore the authorization
  // header is null.

  const token = localStorage.getItem('library-user-token')
  return {
    headers: {
      ...headers,
      authorization: token ? `bearer ${token}` : null,
    }
  }
})

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
})

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root'))


APP.JS
const LOGIN = gql`
  mutation login($username: String!, $password: String!) {
    login(
      username: $username,
      password: $password
    ) {
      value
    }
  }
`

const LOGGED_USER = gql`
  {
    me {
      username
      favoriteGenre
    }
  }
`

const App = () => {
  const [page, setPage] = useState('authors')
  const [token, setToken] = useState(null)
  const [loggedUser, setLoggedUser] = useState(null)
  const loggedUserResult = useQuery(LOGGED_USER)
  const authorResult = useQuery(ALL_AUTHORS)
  const bookResult = useQuery(ALL_BOOKS)
  const client = useApolloClient()

  useEffect(() => {
    setToken(localStorage.getItem('library-user-token'))
  }, [])

  const login = useMutation(LOGIN)

  return (
    <div>
      <LoginForm
        show={page === 'login'}
        login={login}
        setToken={(token) => setToken(token)}
        setPage={setPage}
      />
    </div>
  )
}


LOGINFORM.JS
const LoginForm = (props) => {
  if (!props.show) {
    return null
  }

  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')

  const loginUser = async (event) => {
    event.preventDefault()

    try {
      const result = await props.login({
        variables: { username, password }
      })

      // Context updates here so the token is not yet is the localStorage and
      // therefore LOGGED_USER query returns null

      const token = result.data.login.value
      props.setToken(token)
      localStorage.setItem('library-user-token', token)
      await props.login({
        variables: { username, password }
      })
      props.setToken(token)
      props.setPage('authors')
    } catch(error){
      console.log(error.message);
    }
  }

Каков будет правильный способ запроса зарегистрированного пользователя из базы данных без обновления страницы?

1 Ответ

0 голосов
/ 12 июня 2019

Чтобы изменить и установить токен в заголовках запроса, вы можете использовать промежуточное ПО, таким образом Предложенные документы Apollo :

Другой распространенный способ идентификациисамостоятельно при использовании HTTP стоит отправить вдоль заголовка авторизации.Легко добавить заголовок авторизации к каждому HTTP-запросу, связав вместе Apollo Links.В этом примере мы будем извлекать токен входа из localStorage при каждой отправке запроса:

import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { setContext } from 'apollo-link-context';
import { InMemoryCache } from 'apollo-cache-inmemory';

const httpLink = createHttpLink({
  uri: '/graphql',
});

const authLink = setContext((_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = localStorage.getItem('token');
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    }
  }
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache: new InMemoryCache()
});

Я выполняю ту же настройку в моих приложениях GraphQL.

...