0805登錄_注冊_token_用戶信息_退出-網絡ajax請求2-react-仿低代碼平臺項目

文章目錄

    • 1 JWT
      • 1.1 JWT結構
      • 1.2 工作流程
      • 1.3 優點
      • 1.4 缺點
      • 1.5 安全實踐
      • 1.6. 適用場景
      • 1.7 JWT與OAuth2
      • **8. 示例代碼(Node.js)**
    • 2 用戶mock和api
    • 3 注冊
    • 4 登錄
    • 5 token存儲
    • 6 請求攔截器設置token
    • 6 獲取用戶信息
    • 7 退出登錄
    • 結語

1 JWT

JSON Web Token(JWT)是一種開放標準(RFC 7519),用于在各方之間安全傳輸信息。它通過數字簽名確保數據的完整性和可信性,常用于身份驗證和授權。以下是JWT的詳細介紹:


1.1 JWT結構

JWT由三部分組成,用點(.)分隔:

  • Header(頭部)
    包含令牌類型(typ: "JWT")和簽名算法(如alg: HS256)。
    示例:{"alg": "HS256", "typ": "JWT"} → Base64Url編碼后形成第一部分。
  • Payload(載荷)
    存放聲明(claims),包括預定義聲明(如用戶ID、過期時間)和自定義數據。
    常見預定義聲明:
    • iss(簽發者)、exp(過期時間)、sub(主題)、aud(受眾)等。
      示例:{"sub": "123", "name": "Alice", "exp": 1516239022} → Base64Url編碼后形成第二部分。
  • Signature(簽名)
    對前兩部分的簽名,防止數據篡改。算法由Header指定(如HMAC SHA256)。
    生成方式:HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

最終JWT形式:xxxxx.yyyyy.zzzzz


1.2 工作流程

  1. 用戶登錄:客戶端發送憑證(如用戶名/密碼)到服務器。
  2. 生成JWT:服務器驗證憑證,生成并返回JWT。
  3. 客戶端存儲:客戶端保存JWT(通常存在localStorage或Cookie中)。
  4. 攜帶令牌請求:客戶端在請求頭中添加Authorization: Bearer <JWT>
  5. 服務器驗證:服務器檢查簽名有效性、過期時間等,驗證通過后處理請求。

1.3 優點

  • 無狀態:無需服務器存儲會話信息,適合分布式系統。
  • 跨域支持:適用于API網關、單頁應用(SPA)等場景。
  • 靈活性:載荷可自定義擴展,傳遞非敏感用戶信息。

1.4 缺點

  • 不可廢止:令牌到期前無法強制失效,需借助黑名單或短過期時間。
  • 存儲風險:客戶端存儲不當可能導致XSS攻擊竊取令牌。
  • 信息暴露:載荷僅Base64編碼,需避免存放敏感數據。

1.5 安全實踐

  • 使用HTTPS:防止令牌在傳輸中被截獲。
  • 強簽名算法:如HMAC SHA256或RSA,避免弱算法(如HS256密鑰過短)。
  • 合理設置過期時間:縮短令牌有效期,減少泄露風險。
  • 敏感數據加密:必要時使用JWE(JSON Web Encryption)加密載荷。

1.6. 適用場景

  • API認證:RESTful API的無狀態身份驗證。
  • 單點登錄(SSO):跨多個系統的用戶身份共享。
  • 移動端應用:減少頻繁查詢數據庫的開銷。

1.7 JWT與OAuth2

  • JWT常用作OAuth2的Bearer Token,傳遞用戶身份和權限。
  • OAuth2定義授權流程,JWT是實現令牌的一種方式。

8. 示例代碼(Node.js)

const jwt = require('jsonwebtoken');// 生成JWT
const token = jwt.sign({ userId: 123, role: 'admin' },'your-secret-key',{ expiresIn: '1h' }
);// 驗證JWT
jwt.verify(token, 'your-secret-key', (err, decoded) => {if (err) throw err;console.log(decoded); // { userId: 123, role: 'admin', iat: ..., exp: ... }
});

通過理解JWT的結構、流程及安全實踐,開發者可以有效利用其在現代Web應用中實現安全、高效的身份驗證。

2 用戶mock和api

用戶mock,user.js代碼如下所示:

const Mock = require('mockjs')
const Random = Mock.Randommodule.exports = [{// 獲取用戶url: '/api/user/info',method: 'get',response() {return {errno: 0,data: {username: Random.title(),nickname: Random.cname(),},}}},{// 注冊新用戶url: '/api/user/register',method: 'post',response() {return {errno: 0}}},{// 用戶登錄url: '/api/user/login',method: 'post',response() {return {errno: 0,data: {token: Random.word(20)},}}},
]

前端user.ts 用戶api接口代碼如下所示:

 import request, { ResDataType } from "../services/request";/*** 獲取用戶信息* @returns  用戶信息*/
export async function getUserInfoApi(): Promise<ResDataType> {const url = "/api/user/info";const data = (await request.get(url)) as ResDataType;return data;
}/*** 注冊新用戶* @returns  注冊是否成功*/
export async function registerApi(username: string,password: string,nickname?: string
): Promise<ResDataType> {const url = "/api/user/register";const body = { username, password, nickname: nickname || username };const data = (await request.post(url, body)) as ResDataType;return data;
}/*** 用戶登錄* @returns  token*/
export async function loginApi(username: string,password: string
): Promise<ResDataType> {const url = "/api/user/login";const data = (await request.post(url, { username, password })) as ResDataType;return data;
}

3 注冊

Register.tsx代碼如下所示:

import { FC } from "react";
import { Link, useNavigate } from "react-router-dom";
import { Typography, Space, Form, Input, Button, message } from "antd";
import { UserAddOutlined } from "@ant-design/icons";
import { useRequest } from "ahooks";import { LOGIN_PATHNAME } from "../router";
import { registerApi } from "@/api/user";import styles from "./Register.module.scss";const { Title } = Typography;const Register: FC = () => {const nav = useNavigate();const { run: handleRegister } = useRequest(async (values) => {const { username, password, nickname } = values;return await registerApi(username, password, nickname);},{manual: true,onSuccess() {message.success("注冊成功");// 跳轉登錄頁nav(LOGIN_PATHNAME);},});function onFinish(values: any) {handleRegister(values);}return (<div className={styles.container}><div><Space><Title level={2}><UserAddOutlined /></Title><Title level={2}>注冊新用戶</Title></Space></div><div><FormlabelCol={{ span: 6 }}wrapperCol={{ span: 16 }}onFinish={onFinish}><Form.Itemlabel="用戶名"name="username"rules={[{ required: true, message: "請輸入用戶名" },{type: "string",min: 5,max: 20,message: "字符長度再5-20之間",},{pattern: /^\w+$/,message: "只能是字母數字下劃線",},]}><Input /></Form.Item><Form.Itemlabel="密碼"name="password"rules={[{ required: true, message: "請輸入用戶名" },{min: 8,message: "密碼長度最少8位",},]}><Input.Password /></Form.Item><Form.Itemlabel="確認密碼"name="confirm"dependencies={["password"]}rules={[{required: true,message: "請輸入確認密碼",},({ getFieldValue }) => ({validator(_, value) {if (!value || getFieldValue("password") === value) {return Promise.resolve();} else {return Promise.reject(new Error("兩次密碼不一致"));}},}),]}><Input.Password /></Form.Item><Form.Item label="昵稱" name="nickname"><Input /></Form.Item><Form.Item wrapperCol={{ offset: 6, span: 16 }}><Space><Button type="primary" htmlType="submit">注冊</Button><Link to={LOGIN_PATHNAME}>已有賬戶,登錄</Link></Space></Form.Item></Form></div></div>);
};
export default Register;

執行注冊,成功挑戰登錄頁,如下圖所示:在這里插入圖片描述

4 登錄

登錄頁Login.tsx代碼如下所示:

import { FC, useEffect } from "react";
import { Link, useNavigate } from "react-router-dom";
import { Typography, Space, Form, Input, Button, Checkbox, message } from "antd";
import { UserAddOutlined } from "@ant-design/icons";
import { useRequest } from "ahooks";import { MANAGE_INDEX_PATHNAME, REGISTER_PATHNAME } from "../router";
import { loginApi } from "@/api/user";import styles from "./Register.module.scss";const { Title } = Typography;const USERNAME_KEY = "username";
const PASSWORD_KEY = "password";/*** 瀏覽器本地存儲用戶信息* @param username 用戶名* @param password 密碼*/
function rememberUser(username: string, password: string) {localStorage.setItem(USERNAME_KEY, username);localStorage.setItem(PASSWORD_KEY, password);
}/*** 瀏覽器本地刪除用戶信息* @param username 用戶名* @param password 密碼*/
function deleteUserFromStorage(username: string, password: string) {localStorage.removeItem(USERNAME_KEY);localStorage.removeItem(PASSWORD_KEY);
}/*** 瀏覽器本地獲取用戶信息*/
function getUserInfoFromStorage() {return {username: localStorage.getItem(USERNAME_KEY),password: localStorage.getItem(PASSWORD_KEY),};
}const Login: FC = () => {const nav = useNavigate()// 表單組件初始化const [form] = Form.useForm();useEffect(() => {const { username, password } = getUserInfoFromStorage();form.setFieldsValue({ username, password });// eslint-disable-next-line react-hooks/exhaustive-deps}, []);const { run: handleLogin } = useRequest(async (values) => {const { username, password } = values;return await loginApi(username, password);},{manual: true,onSuccess(res) {message.success("登錄成功")// todo 存儲token// 跳轉我的問卷nav(MANAGE_INDEX_PATHNAME)},});function onFinish(values: any) {const { username, password, remember } = values || {};if (remember) {rememberUser(username, password);} else {deleteUserFromStorage(username, password);}handleLogin({ username, password });}return (<div className={styles.container}><div><Space><Title level={2}><UserAddOutlined /></Title><Title level={2}>用戶登錄</Title></Space></div><div><FormlabelCol={{ span: 6 }}wrapperCol={{ span: 16 }}onFinish={onFinish}initialValues={{ remember: true }}form={form}><Form.Itemlabel="用戶名"name="username"rules={[{ required: true, message: "請輸入用戶名" },{type: "string",min: 5,max: 20,message: "字符長度再5-20之間",},{pattern: /^\w+$/,message: "只能是字母數字下劃線",},]}><Input /></Form.Item><Form.Itemlabel="密碼"name="password"rules={[{ required: true, message: "請輸入用戶名" },{min: 8,message: "密碼長度最少8位",},]}><Input.Password /></Form.Item><Form.ItemwrapperCol={{ offset: 6, span: 16 }}name="remember"valuePropName="checked"><Checkbox>記住我</Checkbox></Form.Item><Form.Item wrapperCol={{ offset: 6, span: 16 }}><Space><Button type="primary" htmlType="submit">登錄</Button><Link to={REGISTER_PATHNAME}>注冊新用戶</Link></Space></Form.Item></Form></div></div>);
};
export default Login;

登錄成功后跳轉我的問卷也,如下圖所示:在這里插入圖片描述

5 token存儲

用戶登錄成功后,需要存儲token,userToken.ts代碼如下所示

/*** @description localStorage管理用戶token* @author gaogzhen*/const KEY = "USER-TOKEN"/*** 設置token* @param token */
export function setToken(token:string) {localStorage.setItem(KEY, token)  
}/*** 獲取token* @returns token*/
export function getToken() {return localStorage.getItem(KEY) || ''
}/*** 刪除token*/
export function removeToken() {localStorage.removeItem(KEY)
}

登錄頁登錄成功后,執行存儲token,Login.tsx代碼如下:

  const { run: handleLogin } = useRequest(async (values) => {const { username, password } = values;return await loginApi(username, password);},{manual: true,onSuccess(res) {message.success("登錄成功");// 存儲tokenconst { token = "" } = res;setToken(token);// 跳轉我的問卷nav(MANAGE_INDEX_PATHNAME);},});

localStorage存儲如下圖哦所示:在這里插入圖片描述

6 請求攔截器設置token

登錄成功后,用戶每次請求需要攜帶token,用戶身份驗證、權限驗證等。這里通過請求攔截器實現,request.ts代碼如下所示:

import axios from "axios";
import { message } from "antd";
import { AUTHORIZATION } from "@/constant";
import { getToken } from "@/utils/userToken";const request = axios.create({timeout: 5000,
});// request攔截:每次請求攜帶token
request.interceptors.request.use((config) => {// todo token 校驗config.headers[AUTHORIZATION] = `Bearer ${getToken()}`;return config;
});// response 攔截:統一處理errno和msg
request.interceptors.response.use((res) => {const resData = (res.data || {}) as ResType;const { errno, data, msg } = resData;if (errno !== 0) {// 錯誤提示if (msg) {message.error(msg);}throw new Error(msg);}return data as any;
});
export default request;export type ResDataType = {[key: string]: any;
};export type ResType = {errno: number;data?: ResDataType;msg?: string;
};

效果如下圖所示:

在這里插入圖片描述

6 獲取用戶信息

用戶登錄之后,用戶信息很多地方需要使用,在學習狀態管理之后再處理,這里我們暫時在用戶信息組件處理。

用戶信息UserInfo.tsx代碼如下所示:

import { FC } from "react";
import { Link } from "react-router-dom";
import { LOGIN_PATHNAME } from "../router/index";
import { useRequest } from "ahooks";
import { getUserInfoApi } from "@/api/user";
import { UserOutlined } from "@ant-design/icons";
import { Button } from "antd";const UserInfo: FC = () => {const { data } = useRequest(getUserInfoApi);const { username, nickname } = data || {};const User = (<><span style={{ color: "#e8e8e8" }}><UserOutlined />{nickname}</span><Button type="link">退出</Button></>);const Login = <Link to={LOGIN_PATHNAME}>登錄</Link>;return <>{username ? User : Login}</>;
};
export default UserInfo;

效果如下圖所示:

在這里插入圖片描述

7 退出登錄

UserInfo.tsx退出功能代碼如下所示:

import { FC } from "react";
import { Link, useNavigate } from "react-router-dom";
import { useRequest } from "ahooks";
import { Button } from "antd";
import { UserOutlined } from "@ant-design/icons";import { LOGIN_PATHNAME } from "../router/index";
import { getUserInfoApi } from "@/api/user";
import { removeToken } from "@/utils/userToken";const UserInfo: FC = () => {const nav = useNavigate()const { data } = useRequest(getUserInfoApi);const { username, nickname } = data || {};function logout() {removeToken()// 跳轉登錄頁nav(LOGIN_PATHNAME)}const User = (<><span style={{ color: "#e8e8e8" }}><UserOutlined />{nickname}</span><Button type="link" onClick={logout}>退出</Button></>);const Login = <Link to={LOGIN_PATHNAME}>登錄</Link>;return <>{username ? User : Login}</>;
};
export default UserInfo;

  • 執行退出,但是右上角還是顯示登錄狀態,后面處理

結語

?QQ:806797785

??倉庫地址:https://gitee.com/gaogzhen

??倉庫地址:https://github.com/gaogzhen

[1]ahook官網[CP/OL].

[2]mock文檔[CP/OL].

[3]Ant Design官網[CP/OL].

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/77589.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/77589.shtml
英文地址,請注明出處:http://en.pswp.cn/web/77589.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

大模型入門

一、模型入門路徑 1. 學習預備知識 編程語言&#xff1a;熟練掌握Python編程語言&#xff0c;包括基本語法、數據結構&#xff08;列表、字典、元組等&#xff09;、面向對象編程、文件操作等。Python有豐富的機器學習和深度學習庫&#xff0c;方便進行大模型的開發和實驗。數…

把dll模塊注入到游戲進程的方法_插APC注入

一、概述 APC是異步過程調用,系統創建線程的時候會為線程創建一個APC隊列,當線程調用SleepEx,WaitSingleObjectEx等函數時,并把線程狀態被設置為可提醒狀態時,線程并不會睡眠,而是檢查APC隊列是否為空,如果不為空,轉去執行APC隊列中的每一項,因此給目標進程中的線程插…

git 如何清空當前分支的歷史提交記錄,僅保留最后一次提交

本方法基于新建 Git 孤立分支實現&#xff1a; 1. ??首先檢出待清理的分支 在 IDEA 右下角檢查當前分支名稱 或執行 git branch 確認。如果不在目標分支上&#xff0c;會顯示 (HEAD detached at xxxxx)&#xff0c;這時需要先切換分支&#xff1a; git checkout 原分支名 2.…

【C++】Googletest應用

Googletest 1 配置 使用cmake配置&#xff1a; 具體文件后面上傳補充 ./test.out --gtest_filterXXXTest.xxx 2 gdb 為了跟蹤流程&#xff0c;可以使用gdb&#xff1b; gdb ./xxx.out gdb --args ./gtest --gtest_filterxxx.xxx設置運行參數 set args --gtest_filterxxx.…

JavaScript:從DOM概述到window對象的常見事件

一、BOM概述 1.BOM的概念 BOM&#xff08;Browser Object Model&#xff09;即瀏覽器對象模型&#xff0c;它提供了獨立于內容而與瀏覽器窗口進行交互的對象&#xff0c;其核心對象是window 2.BOM的構成 BOM比DOM更大&#xff0c;它包含DOM window對象是瀏覽器的頂級對象&a…

qobject與event事件應用

int main(int argc, char *argv[]) {QApplication a(argc, argv);MyWidget mainWidget;mainWidget.setWindowTitle("QObject與事件處理示例");mainWidget.resize(200, 200);mainWidget.show();return a.exec(); }QApplication a(argc, argv);&#xff1a;創建 QAppli…

QTableView復選框居中

目錄 方法一&#xff1a;QSS方法2:自定義復選框委托類一、構造函數 CheckBoxDelegate()二、paint() 方法三、editorEvent() 方法四、關鍵設計要點五、擴展應用場景六、代碼示例&#xff08;補充&#xff09; 方法一&#xff1a;QSS QTableView::indicator {position: relative…

基于QT的仿QQ音樂播放器

一、項目介紹 該項目是基于QT開發的?樂播放軟件&#xff0c;界面友好&#xff0c;功能豐富&#xff0c;主要功能如下&#xff1a; 窗口hand部分&#xff1a; 點擊最小化按鈕&#xff0c;窗口最小化 點擊最大化按鈕&#xff0c;窗口最大化 點擊關閉按鈕&#xff0c;程序退出 …

SQL知識點合集---第二彈

數據一 <select id"listPositionAuditCheckSample" resultType"net.nxe.cloud.content.server.entity.PositionAuditCheckSample"><trim prefixOverrides"union all"><if test"userSampleCount ! null and userSampleCount…

【QT】QT控制硬件

QT控制硬件 1.上位機程序開發2.具體例子控制led燈3. linux中的函數跟QT類里面的函數同名&#xff0c;發生沖突4.示例代碼 1.上位機程序開發 QT做一個上位機程序&#xff0c;控制底層的硬件設備(下位機) 總結&#xff1a; 在構造函數里面去初始化&#xff0c;打開硬件驅動在析…

Flutter介紹、Flutter Windows Android 環境搭建 真機調試

目錄 Flutter介紹 Windows 環境搭建 1.安裝配置JDK 2.下載安裝Android Studio 3.下載配置Flutter SDK ?4.運行Flutter doctor命令檢測環境是否配置成功 ?5.打開Android Studio安裝Flutter/Dart 插件 ?6.插件運行Flutter項目 ?編輯 Flutter Android真機調試 Flut…

Android Studio 中使用 SQLite 數據庫開發完整指南(Kotlin版本)

文章目錄 1. 項目準備1.1 創建新項目1.2 添加必要依賴 2. 數據庫設計3. 實現數據庫3.1 創建實體類 (Entity)3.2 創建數據訪問對象 (DAO)3.3 創建數據庫類 4. 創建 Repository5. 創建 ViewModel6. 實現 UI 層6.1 創建筆記列表 Activityactivity_notes_list.xmlNotesListActivity…

Vue基礎(7)_計算屬性

計算屬性(computed) 一、使用方式&#xff1a; 1.定義計算屬性&#xff1a; 在Vue組件中&#xff0c;通過在 computed 對象中定義計算屬性名稱及對應的計算函數來創建計算屬性。計算函數會返回計算屬性的值。 2.在模板中使用計算屬性&#xff1a; 在Vue的模板中&#xff0c;您…

辛格迪客戶案例 | 華道生物細胞治療生產及追溯項目(CGTS)

01 華道&#xff08;上海&#xff09;生物醫藥有限公司&#xff1a;細胞治療領域的創新先鋒 華道&#xff08;上海&#xff09;生物醫藥有限公司&#xff08;以下簡稱“華道生物”&#xff09;是一家專注于細胞治療技術研發與應用的創新型企業&#xff0c;尤其在CAR-T細胞免疫…

[26] cuda 應用之 nppi 實現圖像格式轉換

[26] cuda 應用之 nppi 實現圖像格式轉換 講述 nppi 接口定義通過nppi實現 bayer 格式轉rgb格式官網參考信息:http://gwmodel.whu.edu.cn/docs/CUDA/npp/group__image__color__debayer.html#details1. 接口定義 官網關于轉換的原理是這么寫的: Grayscale Color Filter Array …

2025“釘耙編程”中國大學生算法設計春季聯賽(8)10031007

題目的意思很好理解找從最左邊到最右邊最短路&#xff08;BFS&#xff09; #include <bits/stdc.h> using namespace std; int a[510][510]; // 存儲網格中每個位置是否有障礙&#xff08;1表示有障礙&#xff0c;0表示無障礙&#xff09; int v[510][510]; // 記錄每…

【Linux】第十一章 管理網絡

目錄 1.TCP/IP網絡模型 物理層&#xff08;Physical&#xff09; 數據鏈路層&#xff08;Date Link&#xff09; 網絡層&#xff08;Internet&#xff09; 傳輸層&#xff08;Transport&#xff09; 應用層&#xff08;Application&#xff09; 2. 對于 IPv4 地址&#…

python_股票月數據趨勢判斷

目錄 前置 代碼 視頻&月數據 前置 1 A股月數據趨勢大致判斷&#xff0c;做一個粗略的篩選 2 邏輯&#xff1a; 1&#xff09;取最近一次歷史最高點 2&#xff09;以1&#xff09;中最高點為分界點&#xff0c;只看右側數據&#xff0c;取最近一次最低點 3&#xf…

Python PyAutoGUI庫【GUI 自動化庫】深度解析與實戰指南

一、核心工作原理 底層驅動機制&#xff1a; 通過操作系統原生API模擬輸入使用ctypes庫調用Windows API/Mac Cocoa/Xlib屏幕操作依賴Pillow庫進行圖像處理 事件模擬流程&#xff1a; #mermaid-svg-1CGDRNzFNEffhvSa {font-family:"trebuchet ms",verdana,arial,sans…

Spring框架allow-bean-definition-overriding詳細解釋

Spring框架中&#xff0c;allow-bean-definition-overriding 是一個控制是否允許覆蓋同名Bean定義的配置屬性。以下是詳細說明&#xff1a; ?1. 作用? ?允許/禁止Bean定義覆蓋?&#xff1a;當Spring容器中檢測到多個同名的Bean定義時&#xff0c;此配置決定是否允許后續的…