Headless WordPress: реализуем вход в приложение под своим логином с помощью JWT

Headless WordPress – идея, которая используется все активнее в среде разработчиков. Я постараюсь раскрыть несколько тем, связанных с этим подходом. В частности, я покажу, как реализовать вход в приложение с помощью JWT.

Мы создадим простое приложение, которое позволит пользователям входить под своим логином. После входа мы выведем пользователю его данные.

Чтобы реализовать вход в приложение с помощью JWT, нам понадобится установить и активировать плагин JWT Authentication for WP REST API.

Подготовка приложения

Давайте создадим наше собственное приложение React с помощью Create React App. Открываем терминал (командную строку) и переходим к каталогу, в которой будет вестись разработка приложения.

Затем используем команду:

npx create-react-app my-app

Здесь вы можете заменить my-app на свое название. Это будет ваш каталог, в котором будет храниться весь код. Я решил назвать каталог headless.

Затем перейдите к этой папке. Запустить приложение можно уже сейчас с помощью команды npm start. Однако давайте сначала установим Gutenberg Components, npm-пакет @wordpress/components. Это позволит нам использовать различные компоненты в своем приложении.

Установить Gutenberg Components можно с помощью команды

npm install @wordpress/components

Поскольку пакет Gutenberg Components не включает в себя классы разметки, мы можем создать свое собственное руководство по CSS-стилям либо использовать существующие стилевые фреймворки, чтобы не тратить на это свое время. Если вы хотите создать приложение, которое будет использоваться в производстве – обязательно подумайте над тем, чтобы создать свою CSS-разметку.

Мы будем использовать Bootstrap 4 для стилей. Установить его можно с помощью команды:

npm install bootstrap

Также нам потребуется процессинг SASS (SCSS), потому нам нужно, чтобы наше приложение могло обрабатывать такие файлы. Для этого используется следующая команда:

npm install node-sass --save

Поскольку мы будем использовать стили Bootstrap и Gutenberg, мы можем удалить App.css и создать App.scss. Поместите следующее внутрь этого нового файла:

@import '~bootstrap/scss/bootstrap.scss';

@import '~@wordpress/components/build-style/style.css';

Теперь он будет компилироваться в файл CSS, который будет включать в себя стили как Boostrap, так и Gutenberg.

Нам нужно будет выполнять запросы POST и GET к нашему сайту WordPress, потому нам понадобится способ реализации этого. Вы можете использовать fetch из API браузера, либо библиотеку. Мы будем использовать библиотеку axios. Она устанавливается с помощью команды

npm install axios

Добавляем логику входа к нашему Headless WordPress

Откройте App.js, чтобы начать добавление логики входа. Мы будем проверять, является ли пользователь залогиненным или нет. Если нет, то мы покажем форму входа. В противном случае будет выводиться консоль.

Давайте скорректируем все импорты в приложении:

import React, { useState, useEffect } from 'react';
import './App.scss';
import '@wordpress/components/build-style/style.css';
import Login from './components/Login';
import Dashboard from './components/Dashboard';

Не беспокойтесь по поводу появляющихся ошибок. Компоненты Dashboard и Login пока что не существуют, потому вы можете получать ошибки компиляции.

Теперь мы можем заменить функцию App на следующее:

function App() {
  const [login, setLogin] = useState( '' );
  const siteURL = 'yoursite_here';

  useEffect(() => {
    const localLogin = localStorage.getItem('login');
    // If we have logged in, set it.
    if ( localLogin ) {
      setLogin( localLogin );
    }
  }, [login]);
 
  return (
    
<div className="App container">
      
<h1>Headless WordPress</h1>

      {
        login && <Dashboard url={siteURL} token={login} setLogin={setLogin} />
      }
      {
        ! login && <Login url={siteURL} setLogin={setLogin}/>
      }

    </div>

  );
}

Что мы здесь сделали:

  • Мы использовали хуки React useState для глобальной обработки информации по логину
  • Мы использовали хуки useEffect для обработки изменений в процессе входа в приложение
  • Если мы залогинены, то в таком случае будет выведен компонент Dashboard
  • Если мы не вошли в приложение, то тогда будет выведен компонент Login

С помощью useEffect наше приложение будет осуществлять вход нашего пользователя (если токен сохранен).

Мы передаем в оба компонента функцию setLogin, которая управляет глобальным состоянием для информации по входу в систему. Это позволит нам, к примеру, предлагать логаут для пользователей.

Создание компонента Login

Чтобы осуществить процедуру входа в наше приложение Headless WordPress для пользователя, нам нужно передать логин и пароль с первой попытки. Для этого нам нужна отдельная форма. Создадим папку components в папке с приложением и создадим файл Login.js.

Поместим в него следующий код:

import React from 'react';
import { TextControl, Button } from '@wordpress/components';

const axios = require('axios');

class Login extends React.Component {
    constructor( props ) {
        super( props );
        this.state = { username: '', password: '' }
        this.handleUsername = this.handleUsername.bind(this);
        this.handlePassword = this.handlePassword.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
}

export default Login;

Мы импортируем Gutenberg-компоненты TextControl и Button, которые мы будем использовать для создания формы входа. У нас также будет еще 3 метода. Эти методы будут использоваться для хранения информации о состоянии входа в приложение, а также о логине пользователя.

Давайте создадим метод render и 2 метода для сохранения информации о состоянии входа. Вы увидите, как мы используем Gutenberg Components.

// ...

class Login extends React.Component {
    // ...

    handleUsername( username ) {
        this.setState( { username } )
    }

    handlePassword( password ) {
        this.setState( { password } )
    }
    render() {
        return (
            
<form className="login" method="post">
                <TextControl className="form-group" label="Username" value={ this.state.username } onChange={ (value) => this.handleUsername( value ) }
                />
                <TextControl className="form-group" label="Password" type="password" onChange={ (value) => this.handlePassword( value ) }
                />
                <Button isPrimary onClick={this.handleSubmit}>Login</Button>
            </form>

        );
    }
}

Второй TextControl также получает password в качестве типа. Когда какой-либо из элементов управления изменится, он будет использовать соответствующий метод для сохранения информации о состоянии входа.

При нажатии на компонент Button мы будем пытаться войти в систему под пользователем. Давайте создадим этот метод сейчас:

//...

class Login extends React.Component {
    //...

    handleSubmit( e ) {
        e.preventDefault();
        const _this = this;
        axios.post( this.props.url + '/wp-json/jwt-auth/v1/token/',
        {
            username: this.state.username,
            password: this.state.password
        })
        .then(function (response) {
            if ( response.status === 200 ) {
                const data = response.data;
                localStorage.setItem( 'login', data.token ); 
                _this.props.setLogin( data.token );
            }
        })
        .catch(function (error) {
            function strip_html_tags(str) {
                if ((str===null) || (str===''))
                    return false;
                else
                str = str.toString();
                return str.replace(/<[^>]*>/g, '');
            }
            alert( strip_html_tags( error.response.data.message ) );
        });
    }

    // ...
}

Мы публикуем имя пользователя и пароль в REST-маршруте для токена jwt. Если пользователь существует, то нам будет возвращен этот токен. Затем мы внесем токен в локальное хранилище, чтобы мы могли получить его при обновлении.

Если этот REST-маршрут вернет нам какие-либо ошибки, мы отобразим их без HTML-тегов.

Все это позволит нашим пользователям войти в приложение WordPress Headless.

Создание компонента Dashboard

В нашем компоненте Dashboard мы будем выводить информацию о нашем пользователе, чтобы мы знали, что мы получили корректного пользователя.

Создаем файл Dashboard.js внутри каталога components и помещаем в него следующее:

import React from 'react';
const axios = require('axios');

class Dashboard extends React.Component {
    constructor( props ) {
        super( props );
        this.state = { user: { } };
        this.Logout = this.Logout.bind(this);
        this.getCurrentUser = this.getCurrentUser.bind(this);
    }
}

export default Dashboard;

Нам также понадобится здесь axios, поскольку мы будем получать информацию о текущем залогиненном пользователе. Мы хотим получить эту информацию как можно скорее, еще когда компонент монтируется.

// ...
class Dashboard extends React.Component {
    // ...

    componentDidMount() {
        this.getCurrentUser();
    }

    getCurrentUser() {
        const token = this.props.token;
        const userURI = this.props.url + '/wp-json/wp/v2/users/me';
        const _this = this;
        axios({
            method: 'POST',
            url: userURI,
            headers: { 'Authorization': 'Bearer ' + token }
        }).then(function (response) {
            if ( response.status === 200 ) {
                const data = response.data;
                _this.setState( {user:data});
                
            }
        })
        .catch(function (error) {
            _this.Logout();
        });

    }
   
}

Мы используем маршрут wp-json/wp/v2/users/me для получения информации о текущем пользователе. Для этого мы передаем заголовок Authorization с нашим Bearer токеном.

Если мы не передадим этот заголовок, то плагин JWT не сможет определить, какой пользователь вошел в приложение.

Давайте теперь выведем информацию о залогиненном пользователе:

// ...

class Dashboard extends React.Component {
    // ...
    
    Logout() {
        localStorage.removeItem('login');
        this.props.setLogin('');
    }

    render() {
        const { nickname, first_name, last_name } = this.state.user;
        return (
            
<div className="dashboard">
                <button type="button" className="btn btn-danger" onClick={this.Logout}>Logout</button>
           
                
<div className="jumbotron">
                    Welcome { nickname }
                    

I think your name is { first_name } { last_name}

                </div>

            </div>

        );
    }
}

У нас есть кнопка логаута, которая также будет использовать переданный метод setLogin. Поскольку мы задали логин в виде пустой строки, приложение выполнит повторный рендеринг и выведет форму входа.

Заключение

Headless WordPress постепенно становится новым стандартом. Вы можете создать такое веб-приложение, которое легко можно будет впоследствии преобразовать в Android или iOS-приложение. Пакет Gutenberg Components значительно экономит время и силы.

Блог про WordPress
Добавить комментарий

Получать новые комментарии по электронной почте.