I'm new to web development and started learning ReactJS.
Till now there is no problem with building simple web apps.
Now I wanted to use authentication using Firebase.
I know how to authenticate a user using Firebase but I'm not able to get how to design frontend to restrict access to certain pages.
Previously, I used PHP and in that I used session
variable and include
to include the parts of HTML to show to the user.
But I don't know how to do it in ReactJS using Firebase.
Initial and failed approach:
I thought of updating this.state.loggedIn
and using that to show the component. But this is not a correct way because I'm sending both the components to display and easily we can change the state of a component using React developer extension in Chrome.
This is my main index.js code:
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'));
And In Login.js, I'm calling the Firebase authentication function.
Just the snippet:
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);
// ...
});
The authentication is working fine and I can see it in the console log.
So, how should I do it in ReactJS + Firebase to authenticate?(Is it posible without using any other packages like react-routes etc?)
Or should I be using Cloud functions for this?
UPDATE:
Everything you link in your html files should always come from your public directory. So, keep your bundled .js
files in your public directory.
I have wrote some time saving tips for beginners. You can find more about that beginners tips here.
It is actually simple.
If you want to send only required html file to the browser, you have to hit the server every time you need a whole different html.
You said that you used PHP. In PHP, we use sessions to know whether a person is logged-in or not.
So, we try to implement it here.
First lets look at how sessions in PHP work. Taken from an SO Answer
In the general situation :
- the session id is sent to the user when his session is created.
- it is stored in a cookie (called, by default,
PHPSESSID
)- that cookie is sent by the browser to the server with each request
- the server (PHP) uses that cookie, containing the session_id, to know which file corresponds to that user.
The data in the sessions files is the content of
$_SESSION
, serialized (ie, represented as a string -- with a function such as serialize) ; and is un-serialized when the file is loaded by PHP, to populate the$_SESSION
array.
Sometimes, the session id is not stored in a cookie, but sent in URLs, too -- but that's quite rare, nowadays.
For more informations, you can take a look at the Session Handling section of the manual, that gives some useful informations.For instance, there is a page about Passing the Session ID, which explains how the session id is passed from page to page, using a cookie, or in URLs -- and which configuration options affect this.
So, session
is just a cookie. Then I guess we can use a cookie to find out about the user login status.
In Firebase, there is a problem with cookies. You can only set cookie name as __session
. Other names are ignored by the Firebase and as a result you can't read cookies on the server.
You need to use Firebase Functions to do some backend work and serve html based on the user login status.
So, setup the Firebase Functions in your project directory. In the root,
$ firebase init functions
Now you have to say to Firebase that any requests coming to your domain must invoke a function.
To do that you have to write rewrites
in your firebase.json
file. Our function name will be main
.
{
"database": {
"rules": "database.rules.json"
},
"hosting": {
"public": "/dev",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites":[{
"source": "**",
"function": "main"
}]
}
}
Now create an index.js
anywhere(Prefer root of the project directory as this is the main file).
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);
Some explanation about above parts:
express
: It is used to process the requests and send the response.
firebase-functions
: It is provided by the Google to use Firebase Functions.
fs
: We read appropriate html according to the user login status from the file system and serve it.
cookie-parser
: We use it to access our cookies easily.
Note: You need to convert it to ES5. So use babel command to convert it(I assume you saved index.js
in your root.)
$ babel index.js -d functions
We are using cookie named __session
to know about the user login status.
If the __session
is set to loggedin
, we send the user Home
html
. Otherwise, we send Login
html
.
Now, the real question is: "Where do we need to set the cookie __session
?"
We set the cookie in the user browser.
We make use of onAuthStateChanged()
.
Call this method in your Login page component
like:
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');
}
});
}
Note: Cookies
object is imported from js-cookie. So, install it.
What we are doing here is:
First the onAuthStateChanged()
is called initially when the page is loaded.
If the user is already logged-in, we enter into if
block.
Then we check for the __session
cookie. This is important because sometimes user can clear all the cookies. When we try to read the cookie in the server, we get undefined
and we send the login page to the user. Process is repeated from 1
.
Then we reload the page. When we reload the page, the user hits the server again. Then we can check for the __session
cookie and send the Home
html
to the user.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With