当前位置: 首页 > news >正文

四川做网站设计公司价格武汉谷歌seo

四川做网站设计公司价格,武汉谷歌seo,平顶山做网站哪家好,如何修改用织梦做的网站的模板目录 项目概述后端实现详解1. 环境准备2. 核心组件用户模型和数据JWT 令牌生成请求加载器(核心认证逻辑) 3. API 端点登录接口受保护的接口 前端实现详解1. 核心 JavaScript 功能通用请求函数登录功能 2. 令牌管理 完整代码运行步骤1. 启动后端服务2. 打…

目录

    • 项目概述
    • 后端实现详解
      • 1. 环境准备
      • 2. 核心组件
        • 用户模型和数据
        • JWT 令牌生成
        • 请求加载器(核心认证逻辑)
      • 3. API 端点
        • 登录接口
        • 受保护的接口
    • 前端实现详解
      • 1. 核心 JavaScript 功能
        • 通用请求函数
        • 登录功能
      • 2. 令牌管理
    • 完整代码
    • 运行步骤
      • 1. 启动后端服务
      • 2. 打开前端页面
      • 3. 测试功能
    • 关键特性
      • 1. Authorization 头认证
      • 2. 令牌生命周期管理
      • 3. 安全特性
      • 4. 用户体验

下面详细介绍如何使用 Flask 后端和 HTML 前端实现 JWT(JSON Web Token)认证系统。

项目概述

这是一个完整的 JWT 认证示例,包含:

  • Flask 后端 API
  • HTML 前端界面
    项目目录
    在这里插入图片描述

后端实现详解

1. 环境准备

首先安装虚拟环境和必要的 Python 库:

uv init
uv venv
source .venv/Script/activate
uv pip install flask flask-cors flask-login itsdangerous

2. 核心组件

用户模型和数据
class User(UserMixin):def __init__(self, id, username, email):self.id = idself.username = usernameself.email = email# 模拟用户数据库
users_db = {'admin': {'id': '1', 'username': 'admin', 'email': 'admin@example.com', 'password': 'password123'},'user': {'id': '2', 'username': 'user', 'email': 'user@example.com', 'password': 'password456'}
}
JWT 令牌生成
# JWT 序列化器
jwt_serializer = Serializer(app.config['SECRET_KEY'])# 生成 JWT 令牌
def generate_token(user_data):payload = {'user_id': user_data['id'],'username': user_data['username']}token = jwt_serializer.dumps(payload)return token
请求加载器(核心认证逻辑)
@login_manager.request_loader
def load_user_from_request(request):# 获取 Authorization 头authorization = request.headers.get('Authorization')if not authorization:return Nonetry:# 移除 'Bearer ' 前缀(如果有)if authorization.startswith('Bearer '):token = authorization[7:]else:token = authorization# 解析 JWT 令牌payload = jwt_serializer.loads(token, max_age=24*3600)  # 24小时有效期# 根据 payload 创建用户对象user = User(id=payload['user_id'],username=payload['username'],email=f"{payload['username']}@example.com")return userexcept Exception as e:return None

3. API 端点

登录接口
@app.route('/api/login', methods=['POST'])
def login():data = request.get_json()username = data.get('username')password = data.get('password')# 验证用户凭证if username in users_db and users_db[username]['password'] == password:user_data = users_db[username]# 生成 JWT 令牌token = generate_token(user_data)return jsonify({'success': True,'message': '登录成功!','access_token': token,'user': {'id': user_data['id'],'username': user_data['username'],'email': user_data['email']}})return jsonify({'success': False,'message': '用户名或密码错误!'}), 401
受保护的接口
@app.route('/api/profile', methods=['GET'])
def get_profile():if current_user.is_authenticated:return jsonify({'success': True,'user': {'id': current_user.id,'username': current_user.username,'email': current_user.email},'message': f'欢迎,{current_user.username}!'})else:return jsonify({'success': False,'message': '未授权访问,请先登录!'}), 401

前端实现详解

1. 核心 JavaScript 功能

通用请求函数
async function makeRequest(url, options = {}) {try {// 如果有令牌,自动添加 Authorization 头if (currentToken) {options.headers = {'Authorization': `Bearer ${currentToken}`,'Content-Type': 'application/json',...options.headers};} else {options.headers = {'Content-Type': 'application/json',...options.headers};}const response = await fetch(API_BASE + url, options);const data = await response.json();return { success: response.ok, data, status: response.status };} catch (error) {return { success: false, error: error.message };}
}
登录功能
async function login() {const username = document.getElementById('username').value;const password = document.getElementById('password').value;const result = await makeRequest('/api/login', {method: 'POST',body: JSON.stringify({ username, password })});if (result.success && result.data.access_token) {// 保存令牌到本地存储currentToken = result.data.access_token;localStorage.setItem('access_token', currentToken);updateLoginStatus(true);}showResponse('loginResponse', result);
}

2. 令牌管理

  • 存储:使用 localStorage 持久化存储 JWT 令牌
  • 自动加载:页面加载时检查本地存储的令牌
  • 自动添加:每个 API 请求自动添加 Authorization

完整代码

html 页面

<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>JWT 认证示例</title><style>body {font-family: Arial, sans-serif;max-width: 800px;margin: 0 auto;padding: 20px;background-color: #f5f5f5;}.container {background: white;padding: 20px;border-radius: 8px;box-shadow: 0 2px 4px rgba(0,0,0,0.1);margin-bottom: 20px;}.form-group {margin-bottom: 15px;}label {display: block;margin-bottom: 5px;font-weight: bold;}input, button {padding: 8px 12px;border: 1px solid #ddd;border-radius: 4px;font-size: 14px;}input {width: 200px;}button {background-color: #007bff;color: white;border: none;cursor: pointer;margin-right: 10px;}button:hover {background-color: #0056b3;}button:disabled {background-color: #6c757d;cursor: not-allowed;}.response {background-color: #f8f9fa;border: 1px solid #dee2e6;border-radius: 4px;padding: 10px;margin-top: 10px;white-space: pre-wrap;font-family: monospace;font-size: 12px;max-height: 300px;overflow-y: auto;}.success {color: #28a745;}.error {color: #dc3545;}.token-display {background-color: #e9ecef;padding: 10px;border-radius: 4px;word-break: break-all;font-family: monospace;font-size: 11px;}.status {padding: 5px 10px;border-radius: 4px;font-weight: bold;display: inline-block;margin-bottom: 10px;}.status.logged-in {background-color: #d4edda;color: #155724;}.status.logged-out {background-color: #f8d7da;color: #721c24;}</style>
</head>
<body><h1>JWT 认证示例 - Authorization 头演示</h1><!-- 登录状态显示 --><div class="container"><h2>登录状态</h2><div id="loginStatus" class="status logged-out">未登录</div><div id="tokenDisplay" class="token-display" style="display: none;"><strong>当前 JWT 令牌:</strong><br><span id="currentToken"></span></div></div><!-- 登录表单 --><div class="container"><h2>用户登录</h2><div class="form-group"><label>用户名:</label><input type="text" id="username" value="admin" placeholder="admin 或 user"></div><div class="form-group"><label>密码:</label><input type="password" id="password" value="password123" placeholder="password123 或 password456"></div><button onclick="login()">登录</button><button onclick="logout()">登出</button><div id="loginResponse" class="response"></div></div><!-- API 测试 --><div class="container"><h2>API 测试(需要 Authorization 头)</h2><button onclick="getProfile()" id="profileBtn" disabled>获取用户资料</button><button onclick="testHeaders()" id="headersBtn" disabled>测试请求头</button><div id="apiResponse" class="response"></div></div><!-- 请求示例 --><div class="container"><h2>请求示例代码</h2><div id="requestExample" class="response">
// 前端发送带 Authorization 头的请求示例:fetch('http://localhost:5000/api/profile', {method: 'GET',headers: {'Authorization': 'Bearer ' + localStorage.getItem('access_token'),'Content-Type': 'application/json'}
})
.then(response => response.json())
.then(data => console.log(data));</div></div><script>const API_BASE = 'http://localhost:5000';let currentToken = null;// 页面加载时检查本地存储的令牌window.onload = function() {const token = localStorage.getItem('access_token');if (token) {currentToken = token;updateLoginStatus(true);}};// 更新登录状态显示function updateLoginStatus(isLoggedIn) {const statusElement = document.getElementById('loginStatus');const tokenDisplay = document.getElementById('tokenDisplay');const currentTokenElement = document.getElementById('currentToken');const profileBtn = document.getElementById('profileBtn');const headersBtn = document.getElementById('headersBtn');if (isLoggedIn && currentToken) {statusElement.textContent = '已登录';statusElement.className = 'status logged-in';tokenDisplay.style.display = 'block';currentTokenElement.textContent = currentToken;profileBtn.disabled = false;headersBtn.disabled = false;} else {statusElement.textContent = '未登录';statusElement.className = 'status logged-out';tokenDisplay.style.display = 'none';profileBtn.disabled = true;headersBtn.disabled = true;}}// 通用请求函数async function makeRequest(url, options = {}) {try {// 如果有令牌,自动添加 Authorization 头if (currentToken) {options.headers = {'Authorization': `Bearer ${currentToken}`,'Content-Type': 'application/json',...options.headers};} else {options.headers = {'Content-Type': 'application/json',...options.headers};}console.log('🚀 发送请求:', {url: API_BASE + url,method: options.method || 'GET',headers: options.headers});const response = await fetch(API_BASE + url, options);const data = await response.json();return { success: response.ok, data, status: response.status };} catch (error) {return { success: false, error: error.message };}}// 显示响应function showResponse(elementId, result) {const element = document.getElementById(elementId);if (result.success) {element.className = 'response success';element.textContent = JSON.stringify(result.data, null, 2);} else {element.className = 'response error';element.textContent = result.error || JSON.stringify(result.data, null, 2);}}// 登录async function login() {const username = document.getElementById('username').value;const password = document.getElementById('password').value;const result = await makeRequest('/api/login', {method: 'POST',body: JSON.stringify({ username, password })});if (result.success && result.data.access_token) {// 保存令牌到本地存储currentToken = result.data.access_token;localStorage.setItem('access_token', currentToken);updateLoginStatus(true);console.log('✅ 登录成功,令牌已保存:', currentToken.substring(0, 50) + '...');}showResponse('loginResponse', result);}// 登出function logout() {currentToken = null;localStorage.removeItem('access_token');updateLoginStatus(false);document.getElementById('loginResponse').textContent = '已登出';document.getElementById('apiResponse').textContent = '';console.log('👋 已登出');}// 获取用户资料(需要 Authorization 头)async function getProfile() {if (!currentToken) {alert('请先登录!');return;}const result = await makeRequest('/api/profile');showResponse('apiResponse', result);}// 测试请求头async function testHeaders() {const result = await makeRequest('/api/test-headers');showResponse('apiResponse', result);}</script>
</body>
</html>

backend_jwt_example.py

from flask import Flask, request, jsonify
from flask_cors import CORS
from flask_login import LoginManager, UserMixin, login_user, current_user
from itsdangerous import URLSafeTimedSerializer as Serializer
import datetimeapp = Flask(__name__)
app.config['SECRET_KEY'] = 'your-secret-key-here'# 启用 CORS
CORS(app, supports_credentials=True)# 初始化 LoginManager
login_manager = LoginManager()
login_manager.init_app(app)# 模拟用户数据
class User(UserMixin):def __init__(self, id, username, email):self.id = idself.username = usernameself.email = emailusers_db = {'admin': {'id': '1', 'username': 'admin', 'email': 'admin@example.com', 'password': 'password123'},'user': {'id': '2', 'username': 'user', 'email': 'user@example.com', 'password': 'password456'}
}# 存储有效的 access_token
valid_tokens = {}# JWT 序列化器
jwt_serializer = Serializer(app.config['SECRET_KEY'])# 生成 JWT 令牌
def generate_token(user_data):payload = {'user_id': user_data['id'],'username': user_data['username']}token = jwt_serializer.dumps(payload)return token# request_loader - 从 Authorization 头获取用户
@login_manager.request_loader
def load_user_from_request(request):# 获取 Authorization 头authorization = request.headers.get('Authorization')if not authorization:return Nonetry:# 移除 'Bearer ' 前缀(如果有)if authorization.startswith('Bearer '):token = authorization[7:]else:token = authorization# 解析 JWT 令牌payload = jwt_serializer.loads(token, max_age=24*3600)  # 24小时有效期# 根据 payload 创建用户对象user = User(id=payload['user_id'],username=payload['username'],email=f"{payload['username']}@example.com")print(f"✅ 成功验证用户: {user.username}")return userexcept Exception as e:print(f"❌ JWT 验证失败: {e}")return None# 登录接口
@app.route('/api/login', methods=['POST'])
def login():data = request.get_json()username = data.get('username')password = data.get('password')# 验证用户凭证if username in users_db and users_db[username]['password'] == password:user_data = users_db[username]# 生成 JWT 令牌token = generate_token(user_data)return jsonify({'success': True,'message': '登录成功!','access_token': token,'user': {'id': user_data['id'],'username': user_data['username'],'email': user_data['email']}})return jsonify({'success': False,'message': '用户名或密码错误!'}), 401# 受保护的接口 - 需要 Authorization 头
@app.route('/api/profile', methods=['GET'])
def get_profile():if current_user.is_authenticated:return jsonify({'success': True,'user': {'id': current_user.id,'username': current_user.username,'email': current_user.email},'message': f'欢迎,{current_user.username}!'})else:return jsonify({'success': False,'message': '未授权访问,请先登录!'}), 401# 测试接口 - 显示请求头信息
@app.route('/api/test-headers', methods=['GET'])
def test_headers():headers = dict(request.headers)authorization = request.headers.get('Authorization')return jsonify({'authorization_header': authorization,'all_headers': headers,'is_authenticated': current_user.is_authenticated,'current_user': current_user.username if current_user.is_authenticated else None})if __name__ == '__main__':print("\n=== JWT 认证示例启动 ===")print("测试用户:")print("  - 用户名: admin, 密码: password123")print("  - 用户名: user, 密码: password456")print("\n接口说明:")print("  - POST /api/login - 登录获取令牌")print("  - GET /api/profile - 获取用户资料(需要 Authorization 头)")print("  - GET /api/test-headers - 查看请求头信息")print("========================\n")app.run(debug=True, host='0.0.0.0', port=5000)

运行步骤

1. 启动后端服务

uv run backend_jwt_example.py

服务将在 http://localhost:5000 启动。

2. 打开前端页面

在浏览器中打开 http://localhost:5000/static/frontend_jwt_example.html 文件。

3. 测试功能

  1. 登录测试

    • 用户名:admin,密码:password123
    • 用户名:user,密码:password456
  2. API 测试

    • 登录成功后,点击"获取用户资料"按钮
    • 点击"测试请求头"查看认证信息
      在这里插入图片描述

关键特性

1. Authorization 头认证

  • 前端自动在请求头中添加 Authorization: Bearer <token>
  • 后端通过 request_loader 自动解析和验证令牌

2. 令牌生命周期管理

  • 令牌有效期:24小时
  • 自动过期处理
  • 本地存储持久化

3. 安全特性

  • CORS 支持跨域请求
  • 令牌签名验证
  • 自动过期检查

4. 用户体验

  • 实时登录状态显示
  • 令牌可视化
  • 详细的错误信息
  • 请求示例代码展示

文章转载自:
http://throstle.rdfq.cn
http://rolling.rdfq.cn
http://bolson.rdfq.cn
http://savarin.rdfq.cn
http://diphyletic.rdfq.cn
http://superman.rdfq.cn
http://galligaskins.rdfq.cn
http://homocentric.rdfq.cn
http://tetryl.rdfq.cn
http://sollicker.rdfq.cn
http://pensionless.rdfq.cn
http://looped.rdfq.cn
http://orthocentre.rdfq.cn
http://catalina.rdfq.cn
http://dripping.rdfq.cn
http://hsia.rdfq.cn
http://unfitted.rdfq.cn
http://heterograft.rdfq.cn
http://ureterolithotomy.rdfq.cn
http://indictor.rdfq.cn
http://xenolith.rdfq.cn
http://profanely.rdfq.cn
http://perfoliate.rdfq.cn
http://bankable.rdfq.cn
http://carthaginian.rdfq.cn
http://ahvenanmaa.rdfq.cn
http://trigeminus.rdfq.cn
http://isogenic.rdfq.cn
http://variolite.rdfq.cn
http://title.rdfq.cn
http://reclame.rdfq.cn
http://boyfriend.rdfq.cn
http://monthly.rdfq.cn
http://accommodator.rdfq.cn
http://greenboard.rdfq.cn
http://sterile.rdfq.cn
http://platypi.rdfq.cn
http://laughter.rdfq.cn
http://cybernation.rdfq.cn
http://calembour.rdfq.cn
http://rubydazzler.rdfq.cn
http://slowdown.rdfq.cn
http://linctus.rdfq.cn
http://counterorder.rdfq.cn
http://perpendicularly.rdfq.cn
http://pissed.rdfq.cn
http://tammy.rdfq.cn
http://larceny.rdfq.cn
http://electrogenesis.rdfq.cn
http://vitellogenin.rdfq.cn
http://ambidexter.rdfq.cn
http://dimorphous.rdfq.cn
http://emplane.rdfq.cn
http://dirigible.rdfq.cn
http://fleckiness.rdfq.cn
http://rustle.rdfq.cn
http://sudor.rdfq.cn
http://lanciform.rdfq.cn
http://acidoid.rdfq.cn
http://counteradvertising.rdfq.cn
http://metastability.rdfq.cn
http://motto.rdfq.cn
http://broomie.rdfq.cn
http://dick.rdfq.cn
http://bilgy.rdfq.cn
http://woof.rdfq.cn
http://agitatedly.rdfq.cn
http://military.rdfq.cn
http://dysarthria.rdfq.cn
http://subvene.rdfq.cn
http://discretionarily.rdfq.cn
http://sabaean.rdfq.cn
http://pertinence.rdfq.cn
http://broadsheet.rdfq.cn
http://populace.rdfq.cn
http://chromomere.rdfq.cn
http://semiaxis.rdfq.cn
http://funnyman.rdfq.cn
http://easier.rdfq.cn
http://desiccant.rdfq.cn
http://photojournalism.rdfq.cn
http://decongestion.rdfq.cn
http://daily.rdfq.cn
http://usable.rdfq.cn
http://revolera.rdfq.cn
http://untense.rdfq.cn
http://bubbly.rdfq.cn
http://somniferous.rdfq.cn
http://cashbook.rdfq.cn
http://eroticism.rdfq.cn
http://rolling.rdfq.cn
http://siegfried.rdfq.cn
http://complacently.rdfq.cn
http://immesh.rdfq.cn
http://tabid.rdfq.cn
http://paulist.rdfq.cn
http://deodorise.rdfq.cn
http://unselfishly.rdfq.cn
http://pernoctate.rdfq.cn
http://dethronement.rdfq.cn
http://www.dt0577.cn/news/122897.html

相关文章:

  • 简单网站设计模板推广网站文案
  • 佛山网站制作哪家企拓客软件怎么样
  • 微信公众号微网站建设武汉大学人民医院光谷院区
  • 最新站长seo网站外链发布平台seo推广外包
  • 校园网站的系统建设seo排名资源
  • 选择热门网站做推广的原因长尾关键词挖掘
  • 百度云服务器做asp网站郴州网络推广公司排名
  • 做实体识别的网站下载班级优化大师并安装
  • 怎么做营销型网站公关
  • 重庆建设管理信息网站百度sem优化师
  • 开发手机网站用什么好百度云网盘登录入口
  • 织梦网站做中英文双语言版本交换链接案例
  • 3d效果图设计制作软件宣城网站seo
  • 电子商务网站建设与维护方法分析不包括哪些百度ai人工智能平台
  • 明年做啥网站能致富营销策略的思路
  • 网站建设手机端官网网络营销方法有什么
  • 百度指数的网站电脑编程培训学校哪家好
  • 郑州网站排名哪家好网站收录大全
  • 泉州有哪些公司是做网站站长工具精品
  • python 做的网站西地那非片吃了多久会硬起来
  • 怎么让别人找你做网站深圳搜索引擎优化推广便宜
  • 网站里+动效是用什么做的如何推广普通话的建议6条
  • 济南做网站建设seo优化知识
  • 小企业一键做网站怎么做电商卖东西
  • 做网站安全联盟解网站推广建站
  • 餐饮网站建设设计sem推广软件
  • 怎么做网站排版网站排名软件有哪些
  • 广州做购物网站中国营销网官网
  • 1个ip可以做几个网站如何做品牌运营与推广
  • 外贸b2b网站大全一b2b平台百度最新推广产品