• 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 areaFacebook login
  • chooseWeb
  • Set the Site URL tohttp://localhost:3000

  • Copy the App Id and App Secret from the Dashboard page into your App

  • inFacebook login > Advanced settings, add:http://localhost:1337/connect/facebook/callbackValid OAuth redirect URIsField.

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.