简介

在本教程中,我们将使用 React 和 FastApi 构建登录身份验证。这将有助于展示我们如何将这两个包用于登录身份验证过程,但在此之前,让我们看看 React 以及 FastApi 是什么。

什么是 FastApi

FastAPI 是一个现代、快速(高性能)的 Web 框架,用于使用 Python 构建 API。它支持同步和异步操作、数据验证、身份验证和交互式 API 文档,所有这些都由 OpenAPI 提供支持。它具有令人兴奋的功能,例如:

什么是 React

React 是一个用户界面开发库。它可以通过与服务器/API 对话来构建全栈应用程序,并在客户端上作为 SPA(单页应用程序)运行。因为它可以胜任并且直接等同于 Angular 或 Vue 等框架,所以 React 经常被称为前端“框架”。

要求

  • Python 已安装。

  • Javascript基础知识。

  • React 基础知识。

  • 有python知识是加分项。

安装 FastAPI

打开我们的终端并 cd 进入我们的project folder并写入以下内容:

mkdir backend

进入全屏模式 退出全屏模式

cd进入刚刚创建的文件夹并运行以下命令:

pip install fastapi

进入全屏模式 退出全屏模式

pip install "uvicorn[standard]"

进入全屏模式 退出全屏模式

pip install pyjwt

进入全屏模式 退出全屏模式

让我们稍后再继续构建我们的前端。

构建前端

让我们创建和应用并安装以下软件包:

npx create-react-app frontend

进入全屏模式 退出全屏模式

接下来我们安装以下软件包:

npm install axios react-router-dom

进入全屏模式 退出全屏模式

完成后,导航到src/index.js并导入BrowserRouter:

import { BrowserRouter } from "react-router-dom";

进入全屏模式 退出全屏模式

然后我们必须用这个替换React.StrictMode标签:

<BrowserRouter>
    <App />
  </BrowserRouter>,

进入全屏模式 退出全屏模式

现在转到app.js并导入:

import { Routes, Route } from "react-router-dom";
import Login from "./login";
import Profile from "./Profile";

进入全屏模式 退出全屏模式

在我们的return()中,让我们删除我们的 div 并将其替换为:

  <div className ="App">
    <Routes><!---what are routes in react-!>
      <Route path="/" element = {<Login/>}/>
      <Route path="/profile" element = {<Profile/>}/>
    </Routes>
    </div>

进入全屏模式 退出全屏模式

在这里,我们正在使用我们将很快创建的页面的路由。接下来让我们在src文件夹中创建一个名为Login.js的文件并粘贴:

export default function Login() {
  return (
    <>
      <h1>login page</h1>
    </>
  );
}

进入全屏模式 退出全屏模式

我们还将创建另一个名为Profile.js的文件并将其粘贴:

export default function Profile() {
  return (
    <>
      <h1>profile page</h1>
    </>
  );
}

进入全屏模式 退出全屏模式

现在让我们开始我们的应用程序:

npm start

进入全屏模式 退出全屏模式

[登录](https://res.cloudinary.com/practicaldev/image/fetch/s--1HpjrPa0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads .s3.amazonaws.com/uploads/articles/1b2a3tlgmltrfge0schq.PNG)

[profile](https://res.cloudinary.com/practicaldev/image/fetch/s--BAsNSBy4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads .s3.amazonaws.com/uploads/articles/33c6aeisc0u5788rsugn.PNG)

如您所见,我们的页面运行良好(还可以通过将/profile添加到 url 来检查配置文件页面)。现在我们已经完成了基础知识,让我们继续设置我们的身份验证。

让我们在src文件夹中创建一个名为Auth.js的新文件并粘贴:

import { useLocation,Navigate } from "react-router-dom"

export const setToken = (token)=>{

    localStorage.setItem('temitope', token)// make up your own token
}

export const fetchToken = (token)=>{

    return localStorage.getItem('temitope')
}

export function RequireToken({children}){

    let auth = fetchToken()
    let location = useLocation()

    if(!auth){

        return <Navigate to='/' state ={{from : location}}/>;
    }

    return children;
}
}

进入全屏模式 退出全屏模式

在这里,我们创建了变量来设置我们的令牌,获取并需要我们的令牌,所以让我们回到我们的app.js并导入我们的令牌:

import { RequireToken } from "./Auth";

进入全屏模式 退出全屏模式

我们将在app.js中添加一些东西。在我们的Route path="/profile"中,让我们通过添加我们的RequireToken来更改元素,因此我们的Route path="/profile"应该如下所示:

<Route
  path="/profile"
  element={
    <RequireToken>
      <Profile />
    </RequireToken>
  }
/>

进入全屏模式 退出全屏模式

当我们保存它并转到我们的应用程序时,我们看到我们的个人资料页面现在受到保护,只能使用有效令牌访问。现在让我们用我们的登录表单完成我们的登录页面。转到登录页面,清除所有内容,然后粘贴:

import { useNavigate } from "react-router";
import { fetchToken } from "./Auth";

export default function Login() {
  const navigate = useNavigate();
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  //check to see if the fields are not empty
  const login = () => {
    if ((username == "") & (password == "")) {
      return;
    } else {
      // make api call to our backend. we'll leave this for later
    }
  };

  return (
    <>
      <div style={{ minHeight: 800, marginTop: 30 }}>
        <h1>login page</h1>
        <div style={{ marginTop: 30 }}>
          {fetchToken() ? (
            <p>you are logged in</p>
          ) : (
            <div>
              <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 onClick={login}>Login</button>
              </form>
            </div>
          )}
        </div>
      </div>
    </>
  );
}

进入全屏模式 退出全屏模式

我们暂时停在那里。是时候在我们的后端工作了。

创建后端

现在让我们打开我们的后端文件夹,创建一个main.py文件并输入以下内容:

from fastapi import FastAPI
from pydantic import BaseModel
import jwt
from pydantic import BaseModel
from fastapi.encoders import jsonable_encoder
from fastapi.middleware.cors import CORSMiddleware


SECERT_KEY = "YOUR_FAST_API_SECRET_KEY"
ALGORITHM ="HS256"
ACCESS_TOKEN_EXPIRES_MINUTES = 800

test_user = {
   "username": "temitope",
    "password": "temipassword",

}

app = FastAPI()

origins = {
    "http://localhost",
    "http://localhost:3000",
}

app.add_middleware(
   CORSMiddleware,
    allow_origins = origins,
    allow_credentials =True,
    allow_methods = ["*"],
    allow_headers= ["*"],
)

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

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

@app.post("/login")
async def user_login(loginitem:LoginItem):


    data = jsonable_encoder(loginitem)

    if data['username']== test_user['username'] and data['password']== test_user['password']:

        encoded_jwt = jwt.encode(data, SECERT_KEY, algorithm=ALGORITHM)
        return {"token": encoded_jwt}

    else:
        return {"message":"login failed"}

进入全屏模式 退出全屏模式

在这里,我们试图:

  • 生成令牌。

  • 定义test user object以检查用户登录凭据

  • 配置我们的CORS以允许我们的 React 应用程序发送 POST 请求

  • 使用test_user对即将到来的数据进行检查。

现在我们已经完成了,让我们回到前端完成事情。前往 login.js 并将其替换为:

import { useNavigate } from "react-router";
import { fetchToken, setToken } from "./Auth";
import { useState } from "react";
import axios from "axios";

export default function Login() {
  const navigate = useNavigate();
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  //check to see if the fields are not empty
  const login = () => {
    if ((username == "") & (password == "")) {
      return;
    } else {
      // make api call to our backend. we'll leave thisfor later
      axios
        .post("http://localhost:8000/login", {
          username: username,
          password: password,
        })
        .then(function (response) {
          console.log(response.data.token, "response.data.token");
          if (response.data.token) {
            setToken(response.data.token);
            navigate("/profile");
          }
        })
        .catch(function (error) {
          console.log(error, "error");
        });
    }
  };

  return (
    <div style={{ minHeight: 800, marginTop: 30 }}>
      <h1>login page</h1>
      <div style={{ marginTop: 30 }}>
        {fetchToken() ? (
          <p>you are logged in</p>
        ) : (
          <div>
            <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>
    </div>
  );
}

进入全屏模式 退出全屏模式

我们还将对我们的profile.js进行更改,所以让我们打开它并粘贴:

import { useNavigate } from "react-router";
export default function Profile() {
  const navigate = useNavigate();

  const signOut = () => {
    localStorage.removeItem("temitope");
    navigate("/");
  };

  return (
    <>
      <div style={{ marginTop: 20, minHeight: 700 }}>
        <h1>Profile page</h1>
        <p>Hello there, welcome to your profile page</p>

        <button onClick={signOut}>sign out</button>
      </div>
    </>
  );
}

进入全屏模式 退出全屏模式

我们完成了,让我们测试我们的应用程序。运行代码:

uvicorn main:app --reload

进入全屏模式 退出全屏模式

[完成](https://res.cloudinary.com/practicaldev/image/fetch/s--jiX8kdCS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads .s3.amazonaws.com/uploads/articles/3bga185xeiqrih0bse69.gif)

结论

在本教程中,我们了解了 FastApi 是什么以及 React 是什么。我们还学习了如何使用这些想法安装 FastApi 和 React 来构建我们的登录身份验证。这是github上的 repo 的链接。快乐编码!

Logo

Python社区为您提供最前沿的新闻资讯和知识内容

更多推荐