Вход в систему React FastAPI Введение

В этом руководстве мы создадим систему входа в систему с помощью React и FastAPI Python.

FastAPI — это фреймворк Python. Это высокопроизводительная платформа, которую вы можете использовать для быстрой настройки вашего серверного приложения.

С другой стороны, React — это среда JavaScript, разработанная Facebook.

Кроме того, если вы из тех, кто лучше учится, просматривая видео, попробуйте этот Вход в React и FastAPI

Теперь давайте приступим к делу.

React и FastAPI Python — создание приложения React (интерфейс)

Давайте настроим новое приложение React. Я буду использовать JavaScript для этого урока. Вы можете отказаться от TypeScript, если хотите.

Откройте командную строку и выполните приведенные ниже команды.

npx create-react-app my-rasyue-app
// once the script runs sucessfully, run below.
cd my-rasyue-app
npm start

Теперь откройте предпочтительную IDE и откройте папку my-rasyue-app.

Настройка нашего приложения React (интерфейс)

На высоком уровне наше приложение React должно:

  1. Иметь страницу входа и страницу профиля (защищенная страница, доступная только после входа в систему)
  2. Имейте кнопку выхода, которая очистит JWT, хранящийся в localStorage.
  3. Страница входа будет иметь форму входа с двумя входами для имени пользователя и электронной почты.
  4. При отправке формы входа мы будем использовать axios для отправки запроса POST на сервер (FastAPI Python)

С этим покончено, давайте взламываем!

Создание страницы входа

Запустите команду ниже, чтобы установить react-router-dom и axios

npm install react-router-dom@6
npm install axios

Откройте свой index.js и вставьте следующее.

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from "react-router-dom";
import 'bootstrap/dist/css/bootstrap.min.css';
ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Мы заключаем App в ‹BrowserRouter›, чтобы разрешить использование Routes в приложении.

Теперь откройте свой App.js и вставьте следующее.

import './App.css';
import {
  Route,
  Routes,
} from "react-router-dom";
import Login from './Login.js'
import Profile from './Profile.js'

function App() {
  return (
    <div className="App">
      <Routes>
        <Route path="/" element={<Login />} />
        <Route
          path="/profile"
          element={<Profile />}
        />
      </Routes>
    </div>
  );
}

export default App;

Теперь нам нужно создать два новых файла Login.js и Profile.js.

Идите вперед и создайте эти два файла.

Внутри Login.js вставьте следующее.

export default function Login(){
    return(
        <>
        
            <div style = {{minHeight: 800, marginTop: 20 }}>
                <h1>Login Page</h1>
            </div>
        
        </>
    )
}

Внутри Profile.js вставьте следующее.

export default function Profile(){
    return(
        <>
        
            <div style = {{minHeight: 800, marginTop: 20 }}>
                <h1>Profile Page</h1>
            </div>
            
        </>
    )
}

Откройте браузер и откройте localhost:3000

У вас должно получиться что-то вроде этого.

На данный момент мы создали 2 новые страницы, Profile и Login. Мы также определили Routes в нашем файле App.js.

Ничего особенного.

Настройка аутентификации и создание защищенной страницы

Пришло время настроить нашу аутентификацию для React.

Создайте новый файл Auth.js и вставьте следующее

import {
    Navigate ,
    useLocation
  } from "react-router-dom";
export const setToken = (token) =>{
    // set token in localStorage
    localStorage.setItem('rasyueToken', token)
}
export const fetchToken = (token) =>{
    // fetch the token
    return localStorage.getItem('rasyueToken')
}

export function RequireToken({children}) {
    
    let auth = fetchToken()
    let location = useLocation();
  
    if (!auth) {
      
      return <Navigate to="/" state={{ from: location }} />;
    }
  
    return children;
}

Откройте App.js и замените следующим.

import './App.css';
import {
  Route,
  Routes,
} from "react-router-dom";
import Login from './Login.js'
import Profile from './Profile.js'
import {RequireToken} from './Auth.js'
function App() {
  return (
    <div className="App">
      <Routes>
        <Route path="/" element={<Login />} />
        <Route
          path="/profile"
          element={
            <RequireToken>
              <Profile />
            </RequireToken>
          }
        />
      </Routes>
    
    </div>
  );
}

export default App;

Чтобы объяснить, что мы сделали, мы сначала создали новый файл Auth.js и внутри него мы определили 3 функции, а именно, setToken, fetchToken и RequireToken

setToken и fetchToken предназначены для установки и извлечения элемента, который мы сохранили в localStorage.

Если вы не знакомы с localStorage, предлагаю вам ознакомиться с ними здесь

RequireToken используется в Route в App.js. Функция получит дочерний путь и определит, разрешен ли пользователю доступ к пути или нет.

Это шаг к тому, чтобы сделать страницу защищенной, в данном случае мы делаем защищенной страницу Profile.

Если токен недоступен, пользователь не сможет получить к нему доступ.

Давайте закончим последнюю часть нашего приложения React для входа в систему.

React FastAPI — заполнение формы входа

Откройте свой Login.js и вставьте следующее.

import {useState} from 'react'
import {setToken, fetchToken} from './Auth.js'
import {useNavigate} from "react-router-dom";
const axios = require('axios');
export default function Login(){
    const navigate = useNavigate();
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const login = () =>{
        if(username === '' && password === ''){
            return
        }else{
            console.log('axios')
            axios.post('http://localhost:8000/login', {
                username: username,
                password: password
            })
            .then(function (response) {
                if(response.data.token){
                    
                    setToken(response.data.token)
                    navigate("/profile");
                }
            })
            .catch(function (error) {
                console.log(error, 'error');
            });
        }
       
    }
    return(
        <>
           
            <div style = {{minHeight: 800, marginTop: 20 }}>
                <h1>Home Page</h1>
                <div style = {{marginTop: 50 }} >
                    {
                        fetchToken() 
                        ? (
                            <p>You are logged in!</p>
                        ) 
                        : (
                            <form>
                            <label style = {{marginRight: 10 }}>Input Username: </label>
                            <input type = 'text'  onChange={ (e)=> setUsername(e.target.value)} />
                            <label style = {{marginRight: 10 }}>Input Password: </label>
                            <input type = 'text'  onChange={ (e)=> setPassword(e.target.value)} />
                            <button type = 'button' onClick = {login}>Login</button>
                        </form>
                        )
                    }
                   
                </div>
            </div>
            
        </>
    )
}

Обновите, и ваша страница будет выглядеть примерно так.

И, наконец, откройте свой Profile.js и замените на следующие.

import {useNavigate} from "react-router-dom";
export default function Profile(){
    const navigate = useNavigate();
    const signOut = () => {
        localStorage.removeItem('rasyueToken')
        navigate("/");
    }

    return(
        <>
        
            <div style = {{minHeight: 800, marginTop: 20 }}>
                <h1>Profile Page</h1>
                <p>Hi, this is your profile</p>
                <div>
                    <button type = 'button' onClick= {signOut}>Sign Out</button>
                </div>
            </div>
            
        </>
    )
}

Если вы протестируете свою систему входа прямо сейчас, она пока не будет работать, нам все еще нужно создать наш сервер.

Давайте создадим наше серверное приложение FastAPI.

React и FastAPI Python — создание приложения FastAPI (бэкэнд)

Давайте настроим наше приложение FastAPI.

Во-первых, убедитесь, что на вашем компьютере установлен Python.

В этом уроке я буду использовать Anaconda и Pycharm, потому что это дает больше контроля над модулями Python, но вам не нужно загружать и Anaconda, и Pycharm.

Просто установка Python и использование любой другой IDE должны работать.

Создайте новую папку и назовите ее как угодно, а внутри создайте новое имя main.py

Прежде чем мы сможем использовать FastAPI, нам нужно сначала установить его через pip. Запустите команду ниже, чтобы установить его.

pip install fastapi
pip install "uvicorn[standard]"
pip install pyjwt

Вход в React FastAPI — создание первой страницы Hello World

Теперь в main.py вставьте следующее.

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}

Запустите приложение FastAPI с помощью uvicorn main:app --reload

У вас должно получиться что-то вроде этого.

Следующим шагом является определение конечной точки, которая будет обрабатывать запрос на вход от внешнего приложения React.

Конечная точка также должна генерировать токен JWT и взаимодействовать с базой данных MongoDB.

React FastAPI Login — создание конечной точки входа

Откройте свой main.py и вставьте следующее.

from fastapi import FastAPI
from typing import Optional
from pydantic import BaseModel
app = FastAPI()

class LoginItem(BaseModel):
    email: str
    password: str

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.post("/login")
async def login_user(login_item: LoginItem):
    return login_item

Как вы можете видеть выше, мы добавили еще одну конечную точку /login, которая принимает только запросы на публикацию, которые приходят вместе с вводом объекта login_item.

Тип LoginItem был определен, чтобы убедиться, что входные данные почтового запроса состоят только из email и password.

Если бы мы протестировали конечную точку с помощью Postman, мы бы получили что-то вроде этого.

React FastAPI Login — изменение конечной точки входа для создания JWT

Теперь, когда у нас работает конечная точка login, следующим шагом будет реализация функции для создания JWT.

Откройте свой main.py и замените следующим.

from fastapi import FastAPI
import jwt
from pydantic import BaseModel
from fastapi.encoders import jsonable_encoder

SECRET_KEY = "my_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 800
dummy_user = {
    "username": "rasyue",
    "password": "rasyuepassword",
}
app = FastAPI()

class LoginItem(BaseModel):
    username: str
    password: str

@app.get("/")
def read_root():
    return {"Hello": "World"}

@app.post("/login")
async def login_user(login_item: LoginItem):
    data = jsonable_encoder(login_item)
    if dummy_user['username'] == data['username'] and dummy_user['username'] == data['username']:
        encoded_jwt = jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM)
        return {'token': encoded_jwt }
    else:
        return {'message': 'Login failed'}

Чтобы объяснить вышесказанное, во-первых, мы добавили в микс модуль JWT, а также the jsonable_encoder.

Затем мы определяем SECRET_KEY, ALGORITHM и ACCESS_TOKEN_EXPIRE_MINUTES, которые мы будем использовать позже, когда захотим сгенерировать наш токен.

Затем мы определяем dummy_user, который является объектом, в котором хранятся наши учетные данные. Обратите внимание, что я изменил email в классе LoginItem на username.

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

Идите вперед и протестируйте свою конечную точку с помощью Postman.

Это все, что касается нашего бэкэнда.

Тестирование нашей формы входа

Наконец, все настроено, давайте протестируем нашу систему входа в систему.

Страница Profile защищена, без токена вы не сможете получить к ней доступ. Попробуйте выйти и посмотреть, что произойдет с токеном.

Конец

Вот и все для этого урока.

Если вам интересно узнать больше об аналогичном руководстве, ознакомьтесь с этим руководством, которое я написал, которому вы можете легко следовать, Создание системы входа в Angular и FastAPI

Больше контента на blog.devgenius.io.