我是Web开发的新手,并开始学习ReactJS。
到目前为止,构建简单的Web应用程序没有问题。
现在我想通过Firebase使用身份验证。
我知道如何使用Firebase对用户进行身份验证,但是我无法获得如何设计前端以限制对某些页面的访问的方法。
以前,我使用PHP,因为我使用了session
变量和include
来包含要显示给用户的HTML部分。
但是我不知道如何使用Firebase在ReactJS中做到这一点。
初始和失败方法:
我考虑过更新this.state.loggedIn
并使用它来显示组件。但这不是正确的方法,因为我要同时发送要显示的两个组件,并且很容易使用Chrome中的React开发人员扩展来更改组件的状态。
这是我的主要index.js代码:
import React from 'react';
import ReactDOM from 'react-dom';
import Login from './components/Login/Login';
import Home from './components/Home/Home';
import fire from './components/Fire';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
loggedIn: false,
};
this.authListener = this.authListener.bind(this);
}
componentDidMount() {
this.authListener();
}
authListener() {
fire.auth().onAuthStateChanged(user => {
if (user) {
// User is signed in.
console.log(user);
this.setState({
loggedIn: true
})
} else {
// No user is signed in.
this.setState({
loggedIn: false
});
}
});
}
render() {
return (
<div>
{this.state.loggedIn ? <Home/> : <Login/>}
</div>
);
}
}
ReactDOM.render(
<App/>, document.getElementById('app'));
然后在Login.js中,我调用Firebase身份验证功能。
只是代码段:
fire
.auth()
.signInWithEmailAndPassword(this.state.email, this.state.password)
.catch(function (error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
console.log(error);
// ...
});
身份验证正常,我可以在控制台日志中看到它。
所以,我应该如何在ReactJS + Firebase中进行身份验证?(可以不使用其他任何包(如react-routes等)来实现吗?)
还是应该为此使用Cloud功能?
答案 0 :(得分:1)
更新:
您在html文件中链接的所有内容都应始终来自公共目录。因此,请将捆绑的.js
文件保留在公共目录中。
我为初学者写了一些省时的技巧。您可以找到有关here初学者提示的更多信息。
这实际上很简单。
如果您只想将所需的html文件发送到浏览器,则每次需要一个完全不同的html时都必须访问服务器。
您说您使用过PHP。在PHP中,我们使用会话来了解某人是否已登录。
因此,我们尝试在此处实现它。
首先让我们看一下PHP中的会话如何工作。取自SO Answer
一般情况下:
- 会话ID是在创建用户会话时发送给用户的。
- 它存储在cookie中(默认情况下称为
PHPSESSID
)- 该cookie由浏览器随每个请求发送到服务器
- 服务器(PHP)使用包含session_id的cookie来知道哪个文件对应于该用户。
会话文件中的数据是
$_SESSION
的内容, 序列化的(即,表示为字符串-具有诸如 serialize);并在加载文件时取消序列化 PHP,以填充$_SESSION
数组。
有时,会话ID不会存储在Cookie中,而是发送到 网址也是如此-但这在当今非常罕见。
有关更多信息,请查看手册的Session Handling部分,其中提供了一些有用的信息。 信息。例如,有一个关于Passing the Session ID的页面, 解释了如何使用 Cookie或URL中-以及哪些配置选项会对此产生影响。
因此,session
只是一个cookie。然后,我想我们可以使用Cookie来了解用户登录状态。
在Firebase中,cookie存在问题。您只能将Cookie名称设置为__session
。 Firebase会忽略其他名称,因此您将无法在服务器上读取Cookie。
您需要使用Firebase Functions进行一些后端工作并根据用户登录状态提供html。
因此,请在您的项目目录中设置Firebase功能。在根中
$ firebase init functions
现在,您必须对Firebase说,到达您域的任何请求都必须调用一个函数。
为此,您必须在rewrites
文件中写入firebase.json
。我们的函数名称为main
。
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "/dev",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites":[{
"source": "**",
"function": "main"
}]
}
}
现在在任何位置创建一个index.js
(首选项目目录的根目录,因为它是主文件)。
index.js
import express from 'express';
import * as functions from 'firebase-functions';
import fs from 'fs';
var cookieParser = require('cookie-parser')
const app = express();
app.use(cookieParser());
app.get('**', (req, res) => {
// Check the custom set cookie for user
// If the user is not logged-in, redirect to Login. Otherwise, redirect to Home page
if (req.cookies.__session == 'loggedin') {
var index = fs.readFileSync(__dirname + '/src/Home/index.html', 'utf8');
}
else {
var index = fs.readFileSync(__dirname + '/src/Login/index.html', 'utf8');
}
res.send(index);
});
export let main = functions.https.onRequest(app);
有关以上部分的一些解释:
express
:用于处理请求和发送响应。
firebase-functions
:由Google提供以使用Firebase功能。
fs
:我们根据文件系统中的用户登录状态读取相应的html并将其提供。
cookie-parser
:我们使用它来轻松访问我们的cookie。
注意:您需要将其转换为ES5。因此,请使用babel命令对其进行转换(我假设您在自己的根目录中保存了index.js
。)
$ babel index.js -d functions
我们正在使用名为__session
的cookie来了解用户登录状态。
如果将__session
设置为loggedin
,我们将发送用户Home
html
。否则,我们发送Login
html
。
现在,真正的问题是:“我们需要在哪里设置Cookie __session
?”
我们在用户浏览器中设置cookie。
我们使用onAuthStateChanged()
。
在您的Login page component
中调用此方法,例如:
componentDidMount() {
this.authListener();
}
authListener() {
fire.auth().onAuthStateChanged(user => {
if (user) {
// User is signed in.
if (Cookies.get('__session') === undefined) {
Cookies.set('__session', 'loggedin', { expires: 3652 });
window.location.reload();
}
} else {
// No user is signed in.
Cookies.remove('__session');
}
});
}
注意:Cookies
对象是从js-cookie导入的。因此,请安装它。
我们在这里做的是:
首先,在页面加载时首先调用onAuthStateChanged()
。
如果用户已经登录,则进入if
块。
然后我们检查__session
cookie。这很重要,因为有时用户可以清除所有cookie。当我们尝试读取服务器中的cookie时,我们得到undefined
并将登录页面发送给用户。从1
开始重复该过程。
然后我们重新加载页面。当我们重新加载页面时,用户再次点击服务器。然后,我们可以检查__session
cookie并将Home
html
发送给用户。
答案 1 :(得分:0)
以前,我使用PHP,因为我使用了会话变量,并且包含要显示给用户的HTML部分。
Firebase可以通过多种方式保持其身份验证状态,如下所述:https://firebase.google.com/docs/auth/web/auth-state-persistence
默认情况下为local
。在网络上,这是localStorage
。对于您来说,这可能是一个巨大的变化,因为通常,身份验证状态处于某种在服务器端和客户端完成的会话或cookie中。
所以,我应该如何在ReactJS + Firebase中进行身份验证?(可以不使用其他任何包(如react-routes等)来实现吗?)
但是使用Firebase,一切都在客户端完成。用户成功通过身份验证后,您将可以按以下说明访问其身份验证令牌:https://firebase.google.com/docs/auth/users#auth_tokens
使用此令牌,您需要按照以下说明在服务器端进行验证:https://firebase.google.com/docs/auth/admin/verify-id-tokens,以保护/保护任何API访问。
但是为了保护React应用程序中的某些页面,您将需要验证某种中间件中localStorage
中的auth状态。最好在您的React生命周期方法之一中为auth状态提供一个侦听器:https://firebase.google.com/docs/reference/js/firebase.auth.Auth#onAuthStateChanged
在您的应用程序中的任何时候,身份验证状态都将变为无效,阻止其查看页面。
答案 2 :(得分:0)
好吧,我向您展示如何在React App上使用firebase Auth。我只是想让您知道这不是正确的方法,您会找到很多实现方法。
因此,让我们开始吧,首先,我正在使用Google Auth,我有一个名为firebase.service.js
的文件,用于处理Auth。该文件如下所示:
import firebase from 'firebase';
import { firebaseConfig } from './private';
export const firebaseApp = firebase.initializeApp(firebaseConfig);
export const auth = firebase.auth();
export const db = firebase.database();
export function loginGoogle(/* options */) {
const provider = new firebase.auth.GoogleAuthProvider();
return firebase.auth().signInWithPopup(provider);
}
firebaseConfig
对象如下:
const firebaseConfig = {
apiKey: API_KEY,
authDomain: AUTH_DOMAIN,
databaseURL: DB_URL,
projectId: PROJECT_ID,
storageBucket: STORE_BUCKET,
messagingSenderId: MSG_SENDER,
};
您可以在Firebase控制台上找到它。
在安装了应用程序的索引文件中,我用身份验证检查包装了ReactDOM.render
方法,以确保是否登录了用户。索引如下:
import React from 'react';
import ReactDOM from 'react-dom';
import firebase from 'firebase';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import { auth } from './services';
auth.setPersistence(firebase.auth.Auth.Persistence.LOCAL).then(() => {
const stop = auth.onAuthStateChanged(() => {
ReactDOM.render(<App />, document.getElementById('root'));
stop();
});
});
registerServiceWorker();
现在,您可以确定,如果用户离开并返回到应用程序,则即使会话仍然有效,也无需再次登录。
下一步是创建PrivateRoute
组件。这是我所做的:
import * as React from 'react';
import { Redirect, Route } from 'react-router-dom';
import PropTypes from 'prop-types';
import { auth } from '../services';
function PrivateRoute({ component: Component, ...rest }) {
const toRender = propsRender => (
auth.currentUser ?
<Component {...propsRender} /> :
<Redirect
to={{
pathname: '/',
state: { from: propsRender.location },
}}
/>
);
return <Route {...rest} render={toRender} />;
}
PrivateRoute.propTypes = {
component: PropTypes.func.isRequired,
path: PropTypes.string.isRequired,
};
export default PrivateRoute;
在这里您可以看到该函数检查是否存在任何登录的用户,否则它将将该用户发送回根路径。请注意,我是从auth
而不是从./services
导入firebase
,这是因为此身份验证已初始化为firebase.service.js
,然后在所有应用程序中使用它。 / p>
现在您可以将此PrivateRoute
用作常用路由,不同之处在于,该路由将检查用户是否已登录。以这个为例:
import * as React from 'react';
import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import { Layout } from 'antd';
import moment from 'moment';
import 'moment/locale/pt-br';
import 'antd/dist/antd.css';
import { PrivateRoute, MainLogged, Login, Navbar, Page404 } from './components';
const { Header } = Layout;
moment.locale('pt-br');
function Main() {
return <Redirect to="/login" />;
}
function App() {
return (
<BrowserRouter>
<Layout>
<Header style={{ paddingLeft: '0', backgroundColor: '#096dd9' }}>
<Navbar />
</Header>
<Switch>
<Route exact path="/" component={Main} />
<Route exact path="/login" component={Login} />
<PrivateRoute path="/app" component={MainLogged} />
<Route component={Page404} />
</Switch>
</Layout>
</BrowserRouter>
);
}
export default App;
您可以看到PrivateRouse
与Route
中的react-router
组件并排使用。
我以为是全部,如果您想问其他任何问题,只需评论一下,如果您想从我的代码中查看项目,就可以找到它here。