- Protected routes and Authentication with React and node.js
- Author: Strapi
- The Nuggets translation Project
- Permanent link to this article: github.com/xitu/gold-m…
- Translator: ElizurHz
- Proofread by: LeviDing
Last weekend I wanted to dig up some pure React without the bells and whistles of Redux-Saga.
So I created a small project in Strapi — one that includes an extensible admin background panel and some built-in features (authorization, upload, permission control…). In conjunction with the Node.js framework, Create a small template using just the Create React App to implement the authorization process.
In this tutorial, we will use Strapi API to provide JSON Web Tokens to quickly implement the basic authorization process and teach you step by step how to use third-party login authorization providers in Strapi (Facebook, GitHub, Google…). To authorize your users to log in (which might be more interesting).
Note: The source code for this article is available atGitHubFound on.
Create a project
To get started, you need to create a Strapi API:
$ npm install strapi@alpha -g
$ strapi new my-app
$ cd my-app && strapi start
Copy the code
And your front-end application:
$ npm install create-react-app -g
$ create-react-app good-old-react-authentication-flow
Copy the code
You need toRegister the first user firstAnd then we can start!
Front-end application architecture
I’m a big fan of the React Boilerplate framework, so I created a similar application to organize my code:
/ SRC └ ─ ─ ─ containers / / React components related to routing | └ ─ ─ ─ the entry of the App / / application | └ ─ ─ ─ AuthPage / / component is responsible for all authorization page | └ ─ ─ ─ ConnectPage / / Responsible for using a third-party provider for authorization | └ ─ ─ ─ HomePage / / only after the user login access to | └ ─ ─ ─ NotFoundPage / / 404 components | └ ─ ─ ─ PrivateRoute / / high order component | └ ─ ─ ─ The components / / display component | └ ─ ─ ─ utils └ ─ ─ ─ auth └ ─ ─ ─ request / / using the fetch auxiliary library network requestCopy the code
Set the route and PrivateRoute
To implement an authenticated view, we first need to create a HoC: high-level component to check if a user can access a particular URL. To do this, we just need to follow the official documentation, modify the fakeAuth example, and use our auth.js auxiliary file:
import React from 'react';
import { Redirect, Route } from 'react-router-dom';
// Utils
import auth from '.. /.. /utils/auth'; const PrivateRoute = ({ component: Component, ... rest }) => ( <Route {... rest} render={props => ( auth.getToken() ! == null ? ( <Component {... props} /> ) : ( <Redirect to={{ pathname:'auth/login',
state: { from: props.location }
}}
/>
):
)} />
);
export default PrivateRoute;
Copy the code
Let’s create the route:
import React, { Component } from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
// Components
import AuthPage from '.. /.. /containers/AuthPage';
import ConnectPage from '.. /.. /containers/ConnectPage';
import HomePage from '.. /.. /containers/HomePage';
import NotFoundPage from '.. /.. /containers/NotFoundPage'; Import PrivateRoute from import PrivateRoute from import PrivateRoute from import PrivateRoute from'.. /.. /containers/PrivateRoute';
// Design
import './styles.css';
class App extends Component {
render() {
return (
<Router>
<div className="App">
<Switch>
{/* A user can't go to the HomePage if is not authenticated */}
); } } export default App;Copy the code
Creating an Authorization View
Now all the routes needed to create the view have been implemented. The way we declare the route allows us to create a component that creates the correct form based on the path.
First, let’s create forms.json to handle creating a form in each Auth view:
- forgot-password
- login
- register
- reset-password
The JSON structure looks like this (you can see that familiarity with customBootstrapClass is required in the Input component) :
{
"views": {
"login": [{"customBootstrapClass": "col-md-12"."label": "Username"."name": "identifier"."type": "text"."placeholder": "[email protected]"
},
{
"customBootstrapClass": "col-md-12"."label": "Password"."name": "password"."type": "password"
},
{
"customBootstrapClass": "col-md-6"."label": "Remember me"."name": "rememberMe"."type": "checkbox"}},"data": {
"login": {
"identifier": ""."password": ""."rememberMe": false}}}Copy the code
Set state when the route changes
If we want to set up the form when the user switches from route Auth /login to route Auth/Register, we need to use the following lifecycle:
componentDidMount() {// Use a function to generate the form in case // the form repeats this.generateForm(this.props); }Copy the code
ComponentWillReceiveProps (nextProps) {/ / because we auth view of all use the same container / / so we need to change the path when updating the UIif (nextProps.location.match.params.authType !== this.props.location.match.params.authType) {
this.generateForm(nextProps);
}
}
Copy the code
The generateForm method is responsible for retrieving the data from the forms.json file above.
Create a view
To create the form, we just need to map the data in forms.json.
handleChange = ({ target }) => this.setState({ value: { ... this.state.value, [target.name]: target.value } });render() {
const inputs = get(forms, ['views', this.props.match.params.authType, []);
return (
<div>
<form onSubmit={this.handleSubmit}>
{inputs.map((input, key) => (
<Input
autoFocus={key === 0}
key={input.name}
name={input.name}
onChange={this.handleChange}
type={input.type}
value={get(this.state.value, [input.name], ' ')}
/>
))}
<Button type="submit" />
</form>
</div>
);
}
Copy the code
At this point, all the views required by the authorized user should have been created! All we need to do is make an API call to access the application.
Publish data to the API
To make the API call, I wrote a secondary file for the request (you can access the demo app here), which we just need to use in our handleSubmit function:
handleSubmit = (e) => {
e.preventDefault();
const body = this.state.value;
const requestURL = 'http://localhost:1337/auth/local';
request(requestURL, { method: 'POST', body: this.state.value})
.then((response) => {
auth.setToken(response.jwt, body.rememberMe);
auth.setUserInfo(response.user, body.rememberMe);
this.redirectUser();
}).catch((err) => {
console.log(err);
});
}
redirectUser = () => {
this.props.history.push('/');
}
Copy the code
There’s nothing fancy here. Once we get the response from the API, we just store the information we need into localStorage or sessionStorage, and we can redirect the user to a HomePage.
We’ve just done the hard part, because it’s so easy to use a third-party licensing provider like Facebook!
Use authorization providers
Whether you choose Facebook, GitHub, or Google, using third-party authorization providers on Strapi to authorize your users to log in is as simple as 🙈. In this example, I’ll show you how to use Facebook’s third-party authorization provider.
Because Strapi doesn’t (yet) provide a Javascript SDK to interface with Strapi’s API and Facebook’s API.
The specific process is as follows:
- User “click to log in using Facebook”
- Redirect the user to another page where he can authorize
- Once authorized, Facebook will redirect the user to your app with a code attached to the URL
- Send this code to Strapi
At this point, we just need to make a request for the API in the componentDidMount lifecycle and redirect the user to the appropriate page based on the response content in the ConnectPage container:
componentDidMount() {
const { match: {params: { provider }}, location: { search } } = this.props;
const requestURL = `http://localhost:1337/auth/${provider}/callback${search}`;
request(requestURL, { method: 'GET' })
.then((response) => {
auth.setToken(response.jwt, true);
auth.setUserInfo(response.user, true);
this.redirectUser('/');
}).catch(err => {
console.log(err.response.payload)
this.redirectUser('/auth/login');
});
}
redirectUser = (path) => {
this.props.history.push(path);
}
Copy the code
Display the authorization provider in AuthPage
To do this, we need a SocialLink component as follows:
/**
*
* SocialLink
*
*/
import React from 'react';
import PropTypes from 'prop-types';
import Button from '.. /.. /components/Button'
function SocialLink({ provider }) {
return (
<a href={`http://localhost:1337/connect/${provider}`} className="link">
<Button type="button" social={provider}>
<i className={`fab fa-${provider}`} />
{provider}
</Button>
</a>
);
}
SocialLink.propTypes = {
provider: PropTypes.string.isRequired,
};
export default SocialLink;
Copy the code
Then we need to add it to the AuthPage:
render() {
const providers = ['facebook'.'github'.'google'.'twitter']; // If you want to remove a provider, just remove it from the array...return( <div> {providers.map(provider => <SocialLink provider={provider} key={provider} />)} {/* Some other code */} </div> ); }Copy the code
That’s all we need to do in our front-end application, now we just need to configure Strapi to enable the third-party authorization provider 😎
Set up the Facebook authorization provider to register users
Go to Facebook Developers and create an app called Test.
- Add in the Product area
Facebook login
- choose
Web
- Set the Site URL to
http://localhost:3000
- Copy the App Id and App Secret from the Dashboard page into your App
- in
Facebook login
>Advanced settings
, add:http://localhost:1337/connect/facebook/callback
到Valid OAuth redirect URIs
Field.
Configuration Strapi
You have now created an application on Facebook that can be used to configure the Facebook provider in your project.
Go to the Providers TAB in the Users & Permissions area and fill out the form as follows:
Don’t forget to save the changes.
conclusion
Hopefully this tutorial will help you log in with user authorization using React and Strapi.
I think it’s not a lot of work and it’s easy! You can find the template I created this weekend using the Create React App here.
Here is another complete example using React Boilerplate, which has fully implemented the entire authorization process. The second example uses React and Redux-Saga, and is the template we use to build our StrAPi-based admin backend.
Feel free to share and leave a comment!
If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.
The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.