身份验证
如果加载的数据并非全部公开,或者您的应用有用户、账户和权限系统,那么您需要一种方式来告诉服务器每个请求关联的用户。
Apollo 客户端使用超级灵活的Apollo Link,它包括多种认证选项。
Cookie
如果您的应用基于浏览器,并且您使用 cookie 与后端进行登录和会话管理,将 cookie 随每个请求发送给网络接口。例如,传递 credentials 选项:credentials: 'same-origin'
如果您的后端服务器与下面一样位于同一域名,否则credentials: 'include'
如果您的后端位于不同域名。
const link = createHttpLink({uri: '/graphql',credentials: 'same-origin'});const client = new ApolloClient({cache: new InMemoryCache(),link,});
此选项传递给HttpLink在发送查询时使用的fetch
实现。
注意:后端还必须允许从请求源中获取凭据。例如,如果在使用流行的npm中'req'包的node.js,以下设置将与上述Apollo客户端设置协同工作:
// enable corsvar corsOptions = {origin: '<insert uri of front-end domain>',credentials: true // <-- REQUIRED backend setting};app.use(cors(corsOptions));
Header
使用HTTP进行身份验证的另一种常见方式是发送授权头发送。通过链式使用Apollo Links向每个HTTP请求添加一个authorization
头部。在本示例中,我们将每次发送请求时从localStorage
中提取登录令牌:
ReactJS示例
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';import { setContext } from '@apollo/client/link/context';const httpLink = createHttpLink({uri: '/graphql',});const authLink = setContext((_, { headers }) => {// get the authentication token from local storage if it existsconst token = localStorage.getItem('token');// return the headers to the context so httpLink can read themreturn {headers: {...headers,authorization: token ? `Bearer ${token}` : "",}}});const client = new ApolloClient({link: authLink.concat(httpLink),cache: new InMemoryCache()});
VueJS示例
import ApolloClient from "apollo-client";import { HttpLink } from "apollo-link-http";import { ApolloLink, concat } from "apollo-link";import { InMemoryCache } from "apollo-cache-inmemory";import { getMainDefinition } from "apollo-utilities";const httpLink = new HttpLink({ uri: process.env.VUE_APP_API_TARGET });const authMiddleware = new ApolloLink((operation, forward) => {// add the authorization to the headersconst token = localStorage.getItem('token');operation.setContext({headers: {authorization: token ? `Bearer ${token}` : "",},});return forward(operation);});export const apolloClient = new ApolloClient({link: concat(authMiddleware, httpLink),cache: new InMemoryCache(),});
服务器可以使用该头部来验证用户并将其附加到GraphQL执行上下文,这样解析器就可以根据用户的角色和权限修改其行为。
退出时重置存储
由于Apollo缓存了您的所有查询结果,当登录状态改变时删除这些结果是很重要的。
最简单的方法确保UI和存储状态反映当前用户权限,是在您的登录或登出过程完成后调用client.resetStore()
。这将导致存储被清除并所有活动查询将被重新取回。如果您只想清除存储而不想重新取回活动查询,则使用client.clearStore()
。另一个选项是刷新页面,这将产生类似的效果。
const PROFILE_QUERY = gql`query CurrentUserForLayout {currentUser {loginavatar_url}}`;function Profile() {const { client, loading, data: { currentUser } } = useQuery(PROFILE_QUERY,{ fetchPolicy: "network-only" });if (loading) {return <p className="navbar-text navbar-right">Loading...</p>;}if (currentUser) {return (<span><p className="navbar-text navbar-right">{currentUser.login} <buttononClick={() => {// call your auth logout code then reset storeApp.logout().then(() => client.resetStore());}}>Log out</button></p></span>);}return (<p className="navbar-text navbar-right"><a href="/login/github">Log in with GitHub</a></p>);}