使用 Apollo 和 React 捕获身份验证失败后如何正确重定向
Posted
技术标签:
【中文标题】使用 Apollo 和 React 捕获身份验证失败后如何正确重定向【英文标题】:How to correctly redirect after catching authentication failure with Apollo and React 【发布时间】:2019-06-17 04:13:06 【问题描述】:我正在编写一个使用 apollo-client
的 React 应用程序,并且我正在使用 apollo-link-error
来全局捕获身份验证错误。我使用createBrowserHistory
进行浏览器历史操作,使用redux
管理我的应用状态。
在身份验证错误时,我想将用户重定向到 /login
页面。
但是,使用 history.push('/login')
和 forceRefresh:false 会更改 URL,但实际上并没有在我的应用程序中导航。
如果我使用forceRefresh:true
,它可以工作,但应用程序会完全重新启动,我想避免这种情况。
const errorLink = onError(( graphQLErrors, networkError ) =>
if(graphQLErrors[0].extensions.code == "UNAUTHENTICATED")
// with forceRefresh:true this works, but causes a nasty
// reload, without the app doesn't navigate, only the url changes
history.push('/login')
);
`
let links = [errorLink, authLink, httpLink];
const link = ApolloLink.from(links);
const client = new ApolloClient(
link: link,
cache: new InMemoryCache(),
connectToDevTools: true,
);
我认为问题在于我没有使用 redux-router
方法进行导航(因此即使 url 发生变化,应用程序也保持不变
问:当我不在组件内时,如何获得类似于使用withRouter()
的redux history
对象?处理这种情况的正确方法是什么?
【问题讨论】:
你想出解决方案了吗? 【参考方案1】:一种可能的解决方案的简短摘要:
-
将所有需要身份验证的路由封装在
<ProtectedRoute>
组件中,该组件将未经身份验证的用户重定向到登录页面。 ProtectedRoute-component 只检查用户是否有有效的令牌,如果没有则重定向用户。
内部错误链接首先删除令牌,或者以某种方式取消验证,然后调用location.reload()
下面有详细的实现。
我找不到任何直接的解决方案。在正常情况下,为了重定向用户,我使用 react-router navigate() 钩子。在错误链接中,我发现无法使用 react-hooks。
但是,我设法解决了实际问题。我实现了 ProtectedRoute 组件,它包装了需要身份验证的应用程序的所有部分:
type ProtectedRouteProps =
path: string;
toRedirect: string;
;
export const ProtectedRoute: FunctionComponent<ProtectedRouteProps> = (
path,
toRedirect,
children,
) =>
return isAuthenticated() ? (
<Route path=path>
children
</Route>
) : (
<Navigate to= pathname: toRedirect />
);
;
type ValidToken = string;
type ExpiredToken = 'Expired token'
type NullToken = '' | null
export type JwtTokenType = (ValidToken | ExpiredToken | NullToken )
export const isNullToken = (token: JwtTokenType) : boolean =>
return (token === '' || token === null)
export const isExpiredToken = (token: JwtTokenType) : boolean =>
return token === "Expired token"
export const isAuthenticated = () : boolean =>
let token = getTokenFromCookies();
return !(isExpiredToken(token) || isNullToken(token));
我是这样使用的:
<Routes>
<Route path="login" element=<LoginPage /> />
<ProtectedRoute path="/*" toRedirect="login">
// protected routes here
</ProtectedRoute>
</Routes>
为了处理未经身份验证的用户的注销和重定向,我实现了两个功能:
// Use this in normal cases
export function useHandleLogout(): () => void
const navigate = useNavigate();
// maybe call other hooks
);
function handleLogout()
navigate("/login");
removeToken();
// do other stuff you want
return handleLogout;
// Use this inside error-link
export const handleLogoutWithoutHook = () =>
// Logout without hook
removeToken();
// do other stuff required when logout
// eslint-disable-next-line no-restricted-globals
location.reload();
// location.reload() after token removed affects user redirect
// when component is wrapped inside <ProtectedRoute> component
;
export const removeToken = () =>
Cookies.remove("jwt-token")
最后在错误链接中:
export const errorLink = onError(
( graphQLErrors, networkError, operation, forward ) =>
if (graphQLErrors)
for (let err of graphQLErrors)
if (err.message.includes('AnonymousUser'))
handleLogoutWithoutHook()
return
if (err.message.includes('Signature has expired'))
handleLogoutWithoutHook()
console.log(err.message)
return forward(operation)
);
【讨论】:
以上是关于使用 Apollo 和 React 捕获身份验证失败后如何正确重定向的主要内容,如果未能解决你的问题,请参考以下文章
graphql_devise 用于 Rails/Graphql/Apollo/React 中的身份验证。 “字段需要身份验证”错误
React、Apollo 2、GraphQL、身份验证。登录后如何重新渲染组件
使用 apollo graphql 对 firebase 身份验证做出反应
React Apollo Link - 如何在使用 <Query /> 和 <Mutation /> 组件之外向 GraphQL 服务器查询身份验证令牌?