加载页面时,Firebase auth.currentUser为null,在页面加载几毫秒后调用authstatechange时,用户加载 [英] Firebase auth.currentUser is null when loading the page, user loaded when authstatechange called after some milli seconds of page load
问题描述
我正在将React与Firebase一起使用来开发一个小型Web应用程序. 为了进行身份验证,我使用了上下文API,并且在上下文中添加了登录用户的详细信息.
I am using React with Firebase to develop a small web app. To take care of authentication, I am using context API and inside context I am adding loggedin user details.
AuthProvider.tsx
AuthProvider.tsx
const AuthProvider: React.FC = props => {
const [state, setState] = useState<IAuthContext>(authInitialState);
console.log("Inside AuthProvider");
useEffect(() => {
auth.onAuthStateChanged( user => {
console.log("Auth State changed and user is ----->", user);
if (user) {
console.log("User value updated to the context")
setState({
...authInitialState,
isAuthenticated:!!user,
permissions:[],
user:user
});
}
const stateChange = {
...authInitialState,
isAuthenticated: !!user,
user
};
// if (!user) {
return setState(stateChange);
// }
});
}, []);
console.log("Rendering AuthProvider", state);
return (
<AuthContext.Provider value={state}>{props.children}</AuthContext.Provider>
);
};
export default AuthProvider;
AuthConsumer.tsx
AuthConsumer.tsx
const withAuthContext = (
Component: React.ComponentClass<any> | React.FunctionComponent<any>
) => {
console.log("Rendering AuthConsumer for ");
return (props: any) => (
<AuthContext.Consumer>
{context => <Component {...props} context={context} />}
</AuthContext.Consumer>
);
};
export default withAuthContext;
PrivateRoute.tsx
PrivateRoute.tsx
interface PrivateRouteProps extends RouteProps {
// tslint:disable-next-line:no-any
component: any;
context: IAuthContext;
}
const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, context: IAuthContext, ...rest } = props;
console.log("Private route for ", props);
return (
<Route
{...rest}
render={(routeProps) =>
props.context.isAuthenticated ? (
<Component {...routeProps} />
) : (
<Redirect
to={{
pathname: '/login',
state: { from: routeProps.location }
}}
/>
)
}
/>
);
};
export default withAuthContext(PrivateRoute);
App.tsx
App.tsx
return (
<BrowserRouter>
<div>
<Switch>
<PublicRoute path="/frame" component={Frame} exact isAuthorized={true}/>
<Route path="/login" component={NewLogin} exact isAuthorized={true}/>
<PrivateRoute path="/nav" component={NavigationBar} exact/>
<PrivateRoute path="/dashboard" component={AnalyticsDashBoard} exact/>
<PrivateRoute path="/subscription" component={OrderSuccess} exact/>
<PrivateRoute path="/onboarding" component={OnBoarding} exact/>
</Switch>
</div>
</BrowserRouter>
);
用户已经登录,并且会话持久性设置为本地. 问题是,当我尝试本地主机/订阅(这是一条私有路由)时,context.isAuthenticated为false,因为尚未触发"onAuthStateChanged"观察者,因此它进入了登录页面,但是在几毫秒内,authStateChange被触发并设置了上下文,但它没有用,因为privateroute认为用户未登录,因此应用程序已经导航到登录状态. 我想了解如何解决此问题的知识.
The user is already loggedin, and session persistence set to local. The problem is, when I try localhost/subscription, which is a private route, context.isAuthenticated is false since "onAuthStateChanged" observer is not triggered yet, so its going to login page, but in few milliseconds, authStateChange triggered and context set, but its no use since application already navigated to login since privateroute thought user not loggedin. I would like to get knowledge on how to overcome this issue.
推荐答案
页面加载后,Firebase将从本地存储中还原用户的凭据,并与服务器一起检查它们是否仍然有效.由于这是对服务器的调用,因此可能要花费一些时间,并且是异步发生的.这就是firebase.auth().currentUser
是null
直到onAuthStateChanged
触发是正常的原因.
When the page loads Firebase restores the user's credentials from local storage and checks with the server whether they are still valid. Since this is a call to the server, it may take some time and happens asynchronously. This is the reason it is normal that firebase.auth().currentUser
is null
until onAuthStateChanged
fires.
您遇到的问题是firebase.auth().currentUser
可能是null
的原因有多种:
The problem you have is that there are multiple reasons firebase.auth().currentUser
can be null
:
-
firebase.auth().currentUser
是null
,因为客户端刚刚加载并且仍在与服务器一起检查凭据. -
firebase.auth().currentUser
是null
,因为客户端已针对服务器检查了凭据,并且客户端未登录. -
firebase.auth().currentUser
是null
,因为用户从未登录过,因此没有要检查的凭据.
firebase.auth().currentUser
isnull
because the client just loaded and it's still checking the credentials with the server.firebase.auth().currentUser
isnull
because the client checked the credentials against the server and the client isn't logged in.firebase.auth().currentUser
isnull
because the user never signed in, so there are no credentials to check.
您要在情况2和3中导航,而不是情况1.
You want to navigate in case 2 and 3, but not case 1.
典型的解决方案是在第一次触发onAuthStateChanged
之前不处理导航.此时,您可以确定已针对服务器检查了凭据,或者没有要检查的凭据,在两种情况下,您都希望导航到登录页面.
The typical solution is to not handle navigation until the first time onAuthStateChanged
has fired. At that point you can be certain that the credentials were checked against the server, or that there were no credentials to check, in both of which cases you'll want to navigate to the sign-in page.
另一个加快速度的方法是,当用户首次登录时,自己将一个小令牌存储在本地存储中,然后在应用加载时读取该令牌.如果存在令牌,则可以区分情况1和情况3,并用它稍早导航到正确的页面.
An additional option to speed this up is to store a small token in local storage yourself when the user signs in for the first time, and then read that when the app loads. If the token is present you can distinguish between case 1 and 3, and use that to navigate to the correct page a bit sooner.
有关此示例,请参阅有关构建移动Web应用的I/O讨论.
For an example of this, see this I/O talk about Architecting Mobile Web Apps.
这篇关于加载页面时,Firebase auth.currentUser为null,在页面加载几毫秒后调用authstatechange时,用户加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!