javascript - 如何使用firebase + react检查Session是否还活着?
问题描述
我已经添加了 Firebase 的授权,它工作得很好。可以登录应用程序并导航,但是当我使用firebase.auth().signOut
observable时onAuthChanged
不会更改/未触发。
对于正确的登录名/密码(错误组合为 400) - 会话已保存,并且我拥有用户凭据:
import React, {useContext, useEffect} from 'react';
import {ROUTES} from '../../../constants';
import {AuthUserContext} from "../../../session";
import history from '../../../helpers/history';
import {useLocation} from "react-router";
import app from "../../../api/firebase";
const WithAuthorization: React.FC = ({children}) => {
const authUser = useContext(AuthUserContext);
const isLogin = useLocation().pathname === ROUTES.LOGIN;
const pushLogin = () => !isLogin && history.push(ROUTES.LOGIN);
useEffect(() => {
const listener = app.auth().onAuthStateChanged(
(user: any) => {
if(!user) {
pushLogin()
} else {
console.log('Signed in with user');
console.log(user);
}
},
(e: any) => {
console.log(e);
}, () => {
console.log('completed');
});
return listener();
}, [])
return <>
{authUser ? children : pushLogin()}
</>;
}
export default WithAuthorization;
但是,当应用程序刷新时,我想检查会话是否处于活动状态。在查看我发现onAuthChanged observable 的文档时,这看起来很简单,但实际上只有在我登录时才会触发。
刷新页面后,或者当我触发时signOut
- 它什么也不做。
这是授权保护组件,它包裹了整个 App:
import React, {useContext, useEffect} from 'react';
import {ROUTES} from '../../../constants';
import {AuthUserContext} from "../../../session";
import history from '../../../helpers/history';
import app from "../../../api/firebase";
const WithAuthorization: React.FC = ({children}) => {
const authUser = useContext(AuthUserContext);
const pushLogin = () => history.push(ROUTES.LOGIN);
useEffect(() => {
const listener = app.auth().onAuthStateChanged(
(user: any) => {
if(!user) pushLogin()
},
(e: any) => {
console.log(e);
}, () => {
console.log('completed');
});
return listener();
}, [])
return <>
{authUser ? children : pushLogin()}
</>;
}
export default WithAuthorization;
我是否缺少身份验证保护组件或可观察的东西?
--- 应用结构:
App 组件非常简单:
import React, {useState} from 'react';
import { Route, Switch, useLocation } from 'react-router';
import { Header, WithAuthorization } from './common';
import DeviceSelection from './DeviceSelection';
import PerfectScroll from 'react-perfect-scrollbar';
import NotFound from './NotFound';
import ThankYou from "./Thankyou";
import 'react-perfect-scrollbar/dist/css/styles.css';
import './App.scss';
import {ROUTES} from "../constants";
import Login from "./Login";
import {AuthUserContext} from "../session";
const App = () => {
const {pathname} = useLocation();
const [authUser, setAuthUser] = useState(null as any);
const isThankYou = pathname === ROUTES.THANKYOU;
return (
<AuthUserContext.Provider
value={authUser}
>
<WithAuthorization>
{!isThankYou && <Header authUser={authUser}/>}
</WithAuthorization>
<div className={`${!isThankYou ? 'appScrollContainer' : ''}`}>
<PerfectScroll>
<Switch>
<Route exact path={[ROUTES.ROOT, ROUTES.HOME]} component={() => <WithAuthorization><DeviceSelection/></WithAuthorization>} />
<Route path={ROUTES.THANKYOU} component={() => <WithAuthorization><ThankYou/></WithAuthorization>} />
<Route path={ROUTES.LOGIN} component={() => <Login setAuthUser={(user: any) => setAuthUser(user)} />}/>
<Route path="*" component={NotFound} />
</Switch>
</PerfectScroll>
</div>
</AuthUserContext.Provider>
);
}
export default App;
Signout 来自 Header 内的一个按钮,该按钮也包含在 WithAuthorization 中:
<Button label={'Sign out'} click={() => app.auth().signOut()} />
登录只做一件事,如果登录成功则重定向到 /home:
import React, {useState} from 'react';
import TextInput from "../common/TextInput";
import history from '../../helpers/history';
import {ROUTES} from "../../constants";
import app, {signInWithEmailAndPassword} from "../../api/firebase";
interface Props {
setAuthUser: (user: any) => void,
}
const Login: React.FC<Props> = ({setAuthUser}) => {
const [form, updateForm] = useState({login: '', password: ''});
const authorize = (user: string, password: string) => {
app.auth().setPersistence(app.auth.Auth.Persistence.SESSION)
.then(() => {
return signInWithEmailAndPassword(user, password).then((user: any) => {
if(user) {
setAuthUser(user);
history.push(ROUTES.ROOT);
return user
}
return null
})
})
.catch((e: any) => {
console.log(e);
})
}
return <div className='form'>
<TextInput
type="text"
placeholder='login'
name={'login'}
value={form.login}
label='Login'
onChange={(e) => updateForm({...form, login: e.currentTarget.value})}
/>
<TextInput
type="password"
placeholder='password'
name={'password'}
value={form.password}
label='Password'
onChange={(e) => updateForm({...form, password: e.currentTarget.value})}
/>
<button onClick={() => authorize(form.login, form.password)}>Submit</button>
</div>
}
export default Login;
FIrebase 使用本身:
import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';
import {DEV_LOCAL_CONFIG, DEV_REMOTE_CONFIG, ORDERS_COLLECTION} from "./const";
firebase.initializeApp(window.location.hostname !== 'localhost' ? DEV_LOCAL_CONFIG : DEV_REMOTE_CONFIG);
/* ==== Authorization ==== */
const signInWithEmailAndPassword = (email: string, password: string) =>
firebase.auth().signInWithEmailAndPassword(email, password);
const signOut = () => firebase.auth().signOut();
export default firebase;
export {
signInWithEmailAndPassword,
signOut
}
解决方案
我的错误仅在于这一行:
return listener();
当我在中定义监听器时useEffect
,它会立即取消订阅。应该:
return () => listener()
除此之外,一切正常。
推荐阅读
- mysql - 创建过程以删除 MySQL 中的新行
- c# - C# windows App 一个特定的圆角
- php - 我在 SQL 中进行查询以计算同一类别的价格,但是当我在数据库中运行查询时,我得到了重复的值
- linker - 未定义对“vtkRenderingOpenGL2_AutoInit_Construct()”collect2 的引用:错误:ld 返回 1 个退出状态
- tkinter - 我想建立一个 bmi 计算器,我对编程完全陌生
- angular - Angular Multiselect Drodown (ng-multiselect-dropdown) - 在外部单击时下拉菜单不关闭
- sapui5 - getOwnerComponent() 在按需嵌入哪个视图的控制器中返回未定义
- css - Vue.js - 如何在删除任何项目时为列表设置动画
- java - 当有多个类似的构建方法时,如何使用构建器来初始化类?
- regex - VBScript - 拒绝所有非英文字符的正则表达式