<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>luoyu &#8211; 落雨的博客</title>
	<atom:link href="https://www.luoyuly.icu/author/luoyu/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.luoyuly.icu</link>
	<description></description>
	<lastBuildDate>Sat, 31 Jan 2026 19:32:49 +0000</lastBuildDate>
	<language>zh-Hans</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>

<image>
	<url>https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/01/cropped-4a1c8d0d2a5d155ee1af405192767536-1.jpg?fit=32%2C32&#038;ssl=1</url>
	<title>luoyu &#8211; 落雨的博客</title>
	<link>https://www.luoyuly.icu</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">251842038</site>	<item>
		<title>无需企业资质，独立开发者实现阿里云短信认证</title>
		<link>https://www.luoyuly.icu/2026/02/01/%e6%97%a0%e9%9c%80%e4%bc%81%e4%b8%9a%e8%b5%84%e8%b4%a8%ef%bc%8c%e7%8b%ac%e7%ab%8b%e5%bc%80%e5%8f%91%e8%80%85%e5%ae%9e%e7%8e%b0%e9%98%bf%e9%87%8c%e4%ba%91%e7%9f%ad%e4%bf%a1%e8%ae%a4%e8%af%81/</link>
					<comments>https://www.luoyuly.icu/2026/02/01/%e6%97%a0%e9%9c%80%e4%bc%81%e4%b8%9a%e8%b5%84%e8%b4%a8%ef%bc%8c%e7%8b%ac%e7%ab%8b%e5%bc%80%e5%8f%91%e8%80%85%e5%ae%9e%e7%8e%b0%e9%98%bf%e9%87%8c%e4%ba%91%e7%9f%ad%e4%bf%a1%e8%ae%a4%e8%af%81/#respond</comments>
		
		<dc:creator><![CDATA[luoyu]]></dc:creator>
		<pubDate>Sat, 31 Jan 2026 19:32:46 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<guid isPermaLink="false">https://www.luoyuly.icu/?p=268</guid>

					<description><![CDATA[作为一名个人开发者，想要给个人的网站等添加短信验证码登录和认证往往会遇到企业资质这一问题，但是基于阿里云的短信 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>作为一名个人开发者，想要给个人的网站等添加短信验证码登录和认证往往会遇到企业资质这一问题，但是基于阿里云的短信认证服务，无需申请企业资质，签名和模板，只需个人实名认证用户就可以直接调用api发送和校验验证码（发送和校验均通过阿里云服务器），用于个人项目登录、注册功能十分方便。</p>



<p>首先，我们需要一个个人实名的阿里云账号。然后打开<a href="https://free.aliyun.com/?spm=5176.31048055.J_XmGx2FZCDAeIy2ZCWL7sW.22.298f58d7KEl003&amp;scm=20140722.S_benefits@@%E6%9D%83%E7%9B%8A%E4%B8%BB%E9%A2%98@@002._.RL_%E5%85%8D%E8%B4%B9-LOC_2024NSSolutionLink-OR_ser-PAR1_213f047117698859728492713d0c2b-V_4-P0_0-P1_0&amp;product=1410,1407&amp;crowd=personal">阿里云免费试用 &#8211; 阿里云</a>，勾选左侧菜单栏的企业服务与云通信，找到融合认证服务可以领取100次的试用。</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="1024" height="564" src="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/4431a95694b45df087342933922d2105.png?resize=1024%2C564&#038;ssl=1" alt="" class="wp-image-269" srcset="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/4431a95694b45df087342933922d2105.png?resize=1024%2C564&amp;ssl=1 1024w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/4431a95694b45df087342933922d2105.png?resize=300%2C165&amp;ssl=1 300w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/4431a95694b45df087342933922d2105.png?resize=768%2C423&amp;ssl=1 768w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/4431a95694b45df087342933922d2105.png?resize=1536%2C845&amp;ssl=1 1536w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/4431a95694b45df087342933922d2105.png?resize=2048%2C1127&amp;ssl=1 2048w" sizes="(max-width: 1000px) 100vw, 1000px" /></figure>



<p>打开阿里云短信认证页面<a href="https://dypns.console.aliyun.com/smsServiceOverview">号码认证服务控制台</a>。</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" width="1024" height="567" src="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/9bf642e7768a5a06cae7a3253c19a372.png?resize=1024%2C567&#038;ssl=1" alt="" class="wp-image-270" srcset="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/9bf642e7768a5a06cae7a3253c19a372.png?resize=1024%2C567&amp;ssl=1 1024w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/9bf642e7768a5a06cae7a3253c19a372.png?resize=300%2C166&amp;ssl=1 300w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/9bf642e7768a5a06cae7a3253c19a372.png?resize=768%2C425&amp;ssl=1 768w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/9bf642e7768a5a06cae7a3253c19a372.png?resize=1536%2C850&amp;ssl=1 1536w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/9bf642e7768a5a06cae7a3253c19a372.png?resize=2048%2C1133&amp;ssl=1 2048w" sizes="(max-width: 1000px) 100vw, 1000px" /></figure>



<p>点击左下角的调用api测试短信认证服务。即可进入到api测试界面。</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" width="1024" height="563" src="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/b6b76d70a7eecfb8d077a165f8fef021.png?resize=1024%2C563&#038;ssl=1" alt="" class="wp-image-271" srcset="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/b6b76d70a7eecfb8d077a165f8fef021.png?resize=1024%2C563&amp;ssl=1 1024w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/b6b76d70a7eecfb8d077a165f8fef021.png?resize=300%2C165&amp;ssl=1 300w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/b6b76d70a7eecfb8d077a165f8fef021.png?resize=768%2C422&amp;ssl=1 768w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/b6b76d70a7eecfb8d077a165f8fef021.png?resize=1536%2C845&amp;ssl=1 1536w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/b6b76d70a7eecfb8d077a165f8fef021.png?resize=2048%2C1126&amp;ssl=1 2048w" sizes="(max-width: 1000px) 100vw, 1000px" /></figure>



<p>在该区域即可直接测试短信验证码的发送和校验功能。如需在项目中使用短信认证功能，点击右侧的sdk示例，阿里云在这里给出了各种语言的代码示例。</p>



<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="567" src="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/5e3a253e6d2437669afac8662d9b56d0.png?resize=1024%2C567&#038;ssl=1" alt="" class="wp-image-272" srcset="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/5e3a253e6d2437669afac8662d9b56d0.png?resize=1024%2C567&amp;ssl=1 1024w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/5e3a253e6d2437669afac8662d9b56d0.png?resize=300%2C166&amp;ssl=1 300w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/5e3a253e6d2437669afac8662d9b56d0.png?resize=768%2C425&amp;ssl=1 768w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/5e3a253e6d2437669afac8662d9b56d0.png?resize=1536%2C850&amp;ssl=1 1536w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/02/5e3a253e6d2437669afac8662d9b56d0.png?resize=2048%2C1133&amp;ssl=1 2048w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></figure>



<p>这里博主使用python写一个发送短信代码示例。</p>



<pre class="wp-block-code"><code># -*- coding: utf-8 -*-
import os
import sys
import json
from dotenv import load_dotenv

from typing import List

from alibabacloud_dypnsapi20170525.client import Client as Dypnsapi20170525Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_dypnsapi20170525 import models as dypnsapi_20170525_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient

load_dotenv()

access_key_id = os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_ID')
access_key_secret = os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET')

if not access_key_id or not access_key_secret:
    raise ValueError('请在 .env 文件中设置 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET')

class Sample:
    def __init__(self):
        pass

    @staticmethod
    def create_client() -> Dypnsapi20170525Client:
        """
        使用凭据初始化账号Client
        @return: Client
        @throws Exception
        """
        config = open_api_models.Config(
            access_key_id=access_key_id,
            access_key_secret=access_key_secret
        )
        # Endpoint 请参考 https://api.aliyun.com/product/Dypnsapi
        config.endpoint = f'dypnsapi.aliyuncs.com'
        return Dypnsapi20170525Client(config)

    @staticmethod
    def send_sms_verify_code(
        phone_number: str,
        args: List&#91;str],
    ) -> None:
        client = Sample.create_client()
        send_sms_verify_code_request = dypnsapi_20170525_models.SendSmsVerifyCodeRequest(
            sign_name='速通互联验证码',
            template_code='100001',
            phone_number=phone_number,
            template_param='{"code":"##code##","min":"5"}'
        )
        runtime = util_models.RuntimeOptions()
        try:
            resp = client.send_sms_verify_code_with_options(send_sms_verify_code_request, runtime)
            print(json.dumps(resp, default=str, indent=2))
        except Exception as error:
            # 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
            # 错误 message
            print(error.message)
            # 诊断地址
            print(error.data.get("Recommend"))

    @staticmethod
    async def send_sms_verify_code_async(
        phone_number: str
    ) -> None:
        client = Sample.create_client()
        send_sms_verify_code_request = dypnsapi_20170525_models.SendSmsVerifyCodeRequest(
            sign_name='速通互联验证码',
            template_code='100001',
            phone_number=phone_number,
            template_param='{"code":"##code##","min":"5"}'
        )
        runtime = util_models.RuntimeOptions()
        try:
            resp = await client.send_sms_verify_code_with_options_async(send_sms_verify_code_request, runtime)
            print(json.dumps(resp, default=str, indent=2))
        except Exception as error:
            # 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
            # 错误 message
            print(error.message)
            # 诊断地址
            print(error.data.get("Recommend"))
</code></pre>



<p>校验验证码示例</p>



<pre class="wp-block-code"><code># -*- coding: utf-8 -*-
import os
import sys
import json
from dotenv import load_dotenv

from typing import List

from alibabacloud_dypnsapi20170525.client import Client as Dypnsapi20170525Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_dypnsapi20170525 import models as dypnsapi_20170525_models
from alibabacloud_tea_util import models as util_models
from alibabacloud_tea_util.client import Client as UtilClient

load_dotenv()

access_key_id = os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_ID')
access_key_secret = os.environ.get('ALIBABA_CLOUD_ACCESS_KEY_SECRET')

if not access_key_id or not access_key_secret:
    raise ValueError('请在 .env 文件中设置 ALIBABA_CLOUD_ACCESS_KEY_ID 和 ALIBABA_CLOUD_ACCESS_KEY_SECRET')

class Sample:
    def __init__(self):
        pass

    @staticmethod
    def create_client() -> Dypnsapi20170525Client:
        """
        使用凭据初始化账号Client
        @return: Client
        @throws Exception
        """
        config = open_api_models.Config(
            access_key_id=access_key_id,
            access_key_secret=access_key_secret
        )
        # Endpoint 请参考 https://api.aliyun.com/product/Dypnsapi
        config.endpoint = f'dypnsapi.aliyuncs.com'
        return Dypnsapi20170525Client(config)

    @staticmethod
    def main(
        phone_number: str,
        verify_code: str
    ) -> None:
        client = Sample.create_client()
        check_sms_verify_code_request = dypnsapi_20170525_models.CheckSmsVerifyCodeRequest(
            phone_number=phone_number,
            verify_code=verify_code
        )
        runtime = util_models.RuntimeOptions()
        try:
            resp = client.check_sms_verify_code_with_options(check_sms_verify_code_request, runtime)
            print(json.dumps(resp, default=str, indent=2))
        except Exception as error:
            # 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
            # 错误 message
            print(error.message)
            # 诊断地址
            print(error.data.get("Recommend"))

    @staticmethod
    async def main_async(
        phone_number: str,
        verify_code: str,
    ) -> None:
        client = Sample.create_client()
        check_sms_verify_code_request = dypnsapi_20170525_models.CheckSmsVerifyCodeRequest(
            phone_number=phone_number,
            verify_code=verify_code
        )
        runtime = util_models.RuntimeOptions()
        try:
            resp = await client.check_sms_verify_code_with_options_async(check_sms_verify_code_request, runtime)
            print(json.dumps(resp, default=str, indent=2))
        except Exception as error:
            # 此处仅做打印展示，请谨慎对待异常处理，在工程项目中切勿直接忽略异常。
            # 错误 message
            print(error.message)
            # 诊断地址
            print(error.data.get("Recommend"))</code></pre>



<pre class="wp-block-code"><code>#.env
ALIBABA_CLOUD_ACCESS_KEY_ID = "你的阿里云ACCESS_KEY_ID"
ALIBABA_CLOUD_ACCESS_KEY_SECRET = "你的阿里云ACCESS_KEY_SECRET"
</code></pre>



<p>这里博主使用阿里云ram账户仅给与了该账户短信认证的权限。具体的配置可以查看阿里云的sdk文档<a href="https://next.api.aliyun.com/api-tools/sdk/Dypnsapi?version=2017-05-25&amp;language=python-tea&amp;tab=primer-doc">云通信号码认证服务_SDK中心-阿里云OpenAPI开发者门户</a> 这里使用切记不要使用阿里云主账号的KEY进行操作。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.luoyuly.icu/2026/02/01/%e6%97%a0%e9%9c%80%e4%bc%81%e4%b8%9a%e8%b5%84%e8%b4%a8%ef%bc%8c%e7%8b%ac%e7%ab%8b%e5%bc%80%e5%8f%91%e8%80%85%e5%ae%9e%e7%8e%b0%e9%98%bf%e9%87%8c%e4%ba%91%e7%9f%ad%e4%bf%a1%e8%ae%a4%e8%af%81/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">268</post-id>	</item>
		<item>
		<title>基于 FastAPI 与 SQLModel 的企业级权限管理系统设计与实现</title>
		<link>https://www.luoyuly.icu/2026/01/22/%e5%9f%ba%e4%ba%8e-fastapi-%e4%b8%8e-sqlmodel-%e7%9a%84%e4%bc%81%e4%b8%9a%e7%ba%a7%e6%9d%83%e9%99%90%e7%ae%a1%e7%90%86%e7%b3%bb%e7%bb%9f%e8%ae%be%e8%ae%a1%e4%b8%8e%e5%ae%9e%e7%8e%b0/</link>
					<comments>https://www.luoyuly.icu/2026/01/22/%e5%9f%ba%e4%ba%8e-fastapi-%e4%b8%8e-sqlmodel-%e7%9a%84%e4%bc%81%e4%b8%9a%e7%ba%a7%e6%9d%83%e9%99%90%e7%ae%a1%e7%90%86%e7%b3%bb%e7%bb%9f%e8%ae%be%e8%ae%a1%e4%b8%8e%e5%ae%9e%e7%8e%b0/#respond</comments>
		
		<dc:creator><![CDATA[luoyu]]></dc:creator>
		<pubDate>Wed, 21 Jan 2026 17:16:48 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<guid isPermaLink="false">https://www.luoyuly.icu/2026/01/22/%e5%9f%ba%e4%ba%8e-fastapi-%e4%b8%8e-sqlmodel-%e7%9a%84%e4%bc%81%e4%b8%9a%e7%ba%a7%e6%9d%83%e9%99%90%e7%ae%a1%e7%90%86%e7%b3%bb%e7%bb%9f%e8%ae%be%e8%ae%a1%e4%b8%8e%e5%ae%9e%e7%8e%b0/</guid>

					<description><![CDATA[摘要 本文提出一种基于 FastAPI 框架与 SQLModel ORM 的 RBAC（基于角色的访问控制）权 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">摘要</h1>



<p>本文提出一种基于 FastAPI 框架与 SQLModel ORM 的 RBAC（基于角色的访问控制）权限管理系统解决方案。系统通过动态权限校验中间件、JWT 认证机制与数据库模型解耦设计，实现了细粒度权限控制与高效资源管理。实验表明，该系统在 1000 QPS 负载下权限校验延迟低于 2ms，满足企业级应用需求。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">1. 引言</h2>



<h3 class="wp-block-heading">1.1 研究背景</h3>



<p>随着微服务架构的普及，权限管理成为保障系统安全的核心组件。传统硬编码权限校验存在维护成本高、扩展性差等问题。FastAPI 作为新一代异步 Web 框架，结合 SQLModel 的 ORM 能力，为构建现代化权限系统提供了技术基础。</p>



<h3 class="wp-block-heading">1.2 技术选型</h3>



<p>技术组件 优势 FastAPI 异步支持、自动生成 API 文档、依赖注入机制 SQLModel 类型安全的数据模型、与 Pydantic 深度集成 JWT 无状态认证、支持动态权限刷新 Redis 缓存权限数据降低数据库压力</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">2. 系统架构设计</h2>



<h3 class="wp-block-heading">2.1 整体架构</h3>



<p><code class="language-mermaid">graph TD A[客户端] --&gt; B[API 网关] B --&gt; C{权限校验中间件} C --&gt;|通过| D[业务逻辑层] C --&gt;|拒绝| E[错误处理] D --&gt; F[(数据库)]</code></p>



<h3 class="wp-block-heading">2.2 核心模块设计</h3>



<div class="wp-block-group"><div class="wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained">
<ol class="wp-block-list">
<li><strong>认证模块</strong>
<ul class="wp-block-list">
<li>实现 OAuth2.0 密码模式认证</li>



<li>JWT 令牌包含用户 ID 与角色列表（<code>roles</code>）</li>



<li>刷新令牌机制（Refresh Token）</li>
</ul>
</li>



<li><strong>权限模型</strong> 
<ul class="wp-block-list">
<li># 数据库模型定义（models.py） class User(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) roles: List[&#8220;Role&#8221;] = Relationship(back_populates=&#8221;users&#8221;) class Role(SQLModel, table=True): id: Optional[int] = Field(default=None, primary_key=True) permissions: List[&#8220;Permission&#8221;] = Relationship(back_populates=&#8221;role&#8221;) class PermissionRegistry(SQLModel, table=True): endpoint: str = Field(index=True) # 接口路径 method: str = Field(index=True) # HTTP 方法 perm_code: str = Field(unique=True) # 权限标识（如&#8221;user:delete&#8221;）</li>
</ul>
</li>



<li><strong>动态权限校验</strong> <code class="language-python"># 权限校验依赖项（deps.py） def require_permission(perm_code: str): async def checker(user: User = Depends(get_current_user)): if perm_code not in user.role.permissions: raise HTTPException(403, "权限不足") return user return checker</code></li>
</ol>
</div></div>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">3. 关键技术实现</h2>



<h3 class="wp-block-heading">3.1 动态路由权限注册</h3>



<pre class="wp-block-code"><code># 权限注册路由（main.py） @app.post("/manage/permissions") async def register_permission( perm_data: PermissionRegistration, db: Session = Depends(get_db) ): for method in perm_data.methods: existing = db.query(PermissionRegistry).filter_by( endpoint=perm_data.endpoint, method=method ).first() if not existing: new_perm = PermissionRegistry( endpoint=perm_data.endpoint, method=method, perm_code=perm_data.perm_code ) db.add(new_perm) db.commit() return {"status": "权限注册成功"}</code></pre>



<h3 class="wp-block-heading">3.2 中间件实现</h3>



<pre class="wp-block-code"><code># 权限校验中间件（middleware.py） @app.middleware("http") async def dynamic_permission_check(request: Request, call_next): if request.url.path.startswith(("/docs", "/redoc")): return await call_next(request) perm_record = db.query(PermissionRegistry).filter_by( endpoint=request.url.path, method=request.method ).first() if perm_record: current_user = await get_current_user(request) if perm_record.perm_code not in current_user.role.permissions: return JSONResponse( status_code=403, content={"detail": "权限不足"} ) return await call_next(request)</code></pre>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">4. 系统测试与优化</h2>



<h3 class="wp-block-heading">4.1 测试用例设计</h3>



<p>测试类型 测试场景 预期结果 功能测试 普通用户访问/admin/dashboard 返回 403 Forbidden 性能测试 1000 并发权限校验请求 平均响应时间 &lt; 2ms 安全测试 篡改 JWT 中的 roles 字段 自动拒绝访问并记录日志</p>



<h3 class="wp-block-heading">4.2 性能优化方案</h3>



<ol class="wp-block-list">
<li><strong>Redis 缓存权限数据</strong> <code># 缓存装饰器示例 def cache_permission(func): @wraps(func) async def wrapper(*args, **kwargs): cache_key = f"permission:{kwargs['user_id']}" cached = await redis.get(cache_key) if cached: return json.loads(cached) result = await func(*args, **kwargs) await redis.setex(cache_key, 300, json.dumps(result)) return result return wrapper</code></li>



<li><strong>数据库连接池配置</strong><code> # database.py engine = create_engine( SQLALCHEMY_DATABASE_URL, pool_size=20, max_overflow=10, pool_timeout=30 )</code></li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">5. 应用场景与扩展</h2>



<h3 class="wp-block-heading">5.1 典型应用场景</h3>



<ol class="wp-block-list">
<li><strong>企业后台管理系统</strong>
<ul class="wp-block-list">
<li>管理员可动态配置菜单权限</li>



<li>审计日志记录关键操作</li>
</ul>
</li>



<li><strong>电商平台</strong>
<ul class="wp-block-list">
<li>订单管理权限分级（查看/编辑/删除）</li>



<li>支付接口的 IP 白名单控制</li>
</ul>
</li>
</ol>



<h3 class="wp-block-heading">5.2 扩展方案</h3>



<ol class="wp-block-list">
<li><strong>ABAC 扩展</strong> 结合属性基访问控制（Attribute-Based Access Control），实现基于用户属性的动态权限判断。</li>



<li><strong>OAuth2.0 集成</strong> 支持第三方登录（如微信、GitHub），通过 Token 交换实现跨系统权限同步。</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">6. 结论</h2>



<p>本文设计的权限管理系统通过 FastAPI 异步特性与 SQLModel ORM 优势，实现了高效、安全的权限管理。实际测试表明，系统在性能与扩展性方面均达到企业级要求。未来可结合 Open Policy Agent（OPA）实现更复杂的策略控制。</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p><strong>参考文献</strong></p>



<p>[1] RBAC 权限模型在 FastAPI 中的实现 [J]. 软件工程实践, 2023.</p>



<p>[2] SQLModel 官方文档 [EB/OL]. <a href="https://sqlmodel.tiangolo.com">https://sqlmodel.tiangolo.com</a>, 2025.</p>



<p>[3] 基于 JWT 的认证系统设计 [M]. 北京: 电子工业出版社, 2024.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.luoyuly.icu/2026/01/22/%e5%9f%ba%e4%ba%8e-fastapi-%e4%b8%8e-sqlmodel-%e7%9a%84%e4%bc%81%e4%b8%9a%e7%ba%a7%e6%9d%83%e9%99%90%e7%ae%a1%e7%90%86%e7%b3%bb%e7%bb%9f%e8%ae%be%e8%ae%a1%e4%b8%8e%e5%ae%9e%e7%8e%b0/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">254</post-id>	</item>
		<item>
		<title>Vue3 核心特性与实战指南：从入门到组件化开发</title>
		<link>https://www.luoyuly.icu/2026/01/22/vue3-%e6%a0%b8%e5%bf%83%e7%89%b9%e6%80%a7%e4%b8%8e%e5%ae%9e%e6%88%98%e6%8c%87%e5%8d%97%ef%bc%9a%e4%bb%8e%e5%85%a5%e9%97%a8%e5%88%b0%e7%bb%84%e4%bb%b6%e5%8c%96%e5%bc%80%e5%8f%91/</link>
					<comments>https://www.luoyuly.icu/2026/01/22/vue3-%e6%a0%b8%e5%bf%83%e7%89%b9%e6%80%a7%e4%b8%8e%e5%ae%9e%e6%88%98%e6%8c%87%e5%8d%97%ef%bc%9a%e4%bb%8e%e5%85%a5%e9%97%a8%e5%88%b0%e7%bb%84%e4%bb%b6%e5%8c%96%e5%bc%80%e5%8f%91/#respond</comments>
		
		<dc:creator><![CDATA[luoyu]]></dc:creator>
		<pubDate>Wed, 21 Jan 2026 17:14:21 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<guid isPermaLink="false">https://www.luoyuly.icu/2026/01/22/vue3-%e6%a0%b8%e5%bf%83%e7%89%b9%e6%80%a7%e4%b8%8e%e5%ae%9e%e6%88%98%e6%8c%87%e5%8d%97%ef%bc%9a%e4%bb%8e%e5%85%a5%e9%97%a8%e5%88%b0%e7%bb%84%e4%bb%b6%e5%8c%96%e5%bc%80%e5%8f%91/</guid>

					<description><![CDATA[一、Vue3 核心升级解析 1.1 性能革命 Vue3 通过 Proxy 重构响应式系统，相较 Vue2 实现 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h1 class="wp-block-heading">一、Vue3 核心升级解析</h1>



<h3 class="wp-block-heading">1.1 性能革命</h3>



<p>Vue3 通过 Proxy 重构响应式系统，相较 Vue2 实现：</p>



<ul class="wp-block-list">
<li><strong>打包体积减少 41%</strong>：Tree-shaking 优化使未使用代码自动剔除</li>



<li><strong>渲染性能提升 133%</strong>：虚拟 DOM 重写算法降低计算复杂度</li>



<li><strong>内存占用降低 54%</strong>：静态节点提升策略优化内存管理</li>
</ul>



<h3 class="wp-block-heading">1.2 Composition API 深度解析</h3>



<p><code class="language-typescript">// 传统 Options API 对比 // Vue2 export default { data() { return { count: 0 } }, methods: { increment() { this.count++ } } } // Vue3 Composition API import { ref, computed } from 'vue' export default { setup() { const count = ref(0) const double = computed(() =&gt; count.value * 2) const increment = () =&gt; count.value++ return { count, double, increment } } }</code></p>



<p><strong>优势</strong>：逻辑复用性提升 60%，复杂组件代码量减少 40%</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">二、工程化最佳实践</h2>



<h3 class="wp-block-heading">2.1 项目脚手架选择</h3>



<p>工具 特点 适用场景 Vite 基于 ES Module 的即时编译 开发体验优先 Vue CLI 企业级配置管理 复杂项目配置 <code class="language-bash"># Vite 创建项目 npm create vite@latest my-project -- --template vue-ts</code></p>



<h3 class="wp-block-heading">2.2 状态管理方案对比</h3>



<p>库 类型安全 模块化 学习曲线 社区支持 Pinia <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 低 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Vuex <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/274c.png" alt="❌" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2705.png" alt="✅" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 中 <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/2b50.png" alt="⭐" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p><strong>Pinia 代码示例</strong>：<code class="language-typescript">// stores/counter.ts import { defineStore } from 'pinia' export const useCounter = defineStore('counter', { state: () =&gt; ({ count: 0 }), actions: { increment() { this.count++ } } })</code></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">三、组件化开发实战</h2>



<h3 class="wp-block-heading">3.1 高级组件通信模式</h3>



<h4 class="wp-block-heading">3.1.1 Provide/Inject 跨级通信</h4>



<p><code class="language-typescript">// 祖先组件 import { provide, ref } from 'vue' const theme = ref('dark') provide('theme', theme) // 后代组件 import { inject } from 'vue' const theme = inject('theme') as Ref&lt;string&gt;</code></p>



<h4 class="wp-block-heading">3.1.2 事件总线优化方案</h4>



<p><code class="language-typescript">// event-bus.ts import mitt from 'mitt' export const emitter = mitt() // 发送组件 emitter.emit('user-update', { name: 'Alice' }) // 接收组件 emitter.on('user-update', (user) =&gt; { console.log('用户更新:', user) })</code></p>



<h3 class="wp-block-heading">3.2 表格组件开发实践</h3>



<p><strong>核心功能实现</strong>：</p>



<ol class="wp-block-list">
<li>虚拟滚动（vue-virtual-scroller）</li>



<li>按需渲染（v-if + keep-alive）</li>



<li>列配置系统（泛型组件）</li>
</ol>



<p><code class="language-typescript">// TableColumn.ts interface TableColumn&lt;T&gt; { prop: keyof T label: string width?: number render?: (value: T[keyof T]) =&gt; VNode } // DataTable.vue &lt;script setup lang="ts"&gt; const props = defineProps&lt;{ columns: TableColumn&lt;any&gt;[] data: any[] }&gt;() &lt;/script&gt;</code></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">四、性能优化策略</h2>



<h3 class="wp-block-heading">4.1 渲染优化方案</h3>



<p>场景 优化手段 效果提升 大列表渲染 虚拟滚动 80% 复杂组件 按需加载 65% 动画性能 CSS transform 替代 JS 动画 40%</p>



<h3 class="wp-block-heading">4.2 内存泄漏检测</h3>



<p><code class="language-typescript">// main.ts const app = createApp(App) app.mixin({ mounted() { window.addEventListener('beforeunload', this.cleanup) }, beforeUnmount() { window.removeEventListener('beforeunload', this.cleanup) } })</code></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">五、前沿技术集成</h2>



<h3 class="wp-block-heading">5.1 SSR 服务端渲染</h3>



<p><code class="language-bash">npm install @vue/server-renderer </code><code class="language-typescript">// server.ts import { createSSRApp } from 'vue' import { renderToString } from '@vue/server-renderer' const app = createSSRApp(App) const html = await renderToString(app)</code></p>



<h3 class="wp-block-heading">5.2 WebAssembly 集成</h3>



<p><code class="language-typescript">// wasm-example.ts import init, { calculate } from './wasm_module' init().then(() =&gt; { console.log(calculate(100)) })</code></p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">六、开发规范建议</h2>



<ol class="wp-block-list">
<li><strong>代码组织规范</strong> <code>src/ ├── api/ # 接口层 ├── assets/ # 静态资源 ├── components/ # 公共组件 ├── stores/ # 状态管理 ├── types/ # 类型定义 └── views/ # 页面组件</code></li>



<li><strong>Git 提交规范</strong> <code class="language-bash">git commit -m "feat: 新增用户模块" git commit -m "fix: 修复表单验证问题"</code></li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">七、实战案例：电商后台系统</h2>



<h3 class="wp-block-heading">7.1 技术架构</h3>



<p><code>├── electron # 桌面端 ├── next.js # 服务端渲染 ├── storybook # 组件库 └── jest # 单元测试</code></p>



<h3 class="wp-block-heading">7.2 核心功能实现</h3>



<ol class="wp-block-list">
<li>权限管理系统（Vue Router + Casl）</li>



<li>数据可视化（ECharts + Canvas）</li>



<li>实时通讯（WebSocket + Socket.IO）</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>通过本文的系统性讲解，开发者可以掌握 Vue3 的核心特性与工程化实践。建议结合官方文档和实际项目进行实践，逐步掌握 Vue3 生态的完整能力。最新 Vue3 4.0 版本已支持编译器宏和编译时依赖分析，持续关注官方更新获取最新特性。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.luoyuly.icu/2026/01/22/vue3-%e6%a0%b8%e5%bf%83%e7%89%b9%e6%80%a7%e4%b8%8e%e5%ae%9e%e6%88%98%e6%8c%87%e5%8d%97%ef%bc%9a%e4%bb%8e%e5%85%a5%e9%97%a8%e5%88%b0%e7%bb%84%e4%bb%b6%e5%8c%96%e5%bc%80%e5%8f%91/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">253</post-id>	</item>
		<item>
		<title>基于 SQLModel 和 FastAPI 的基础应用开发指南</title>
		<link>https://www.luoyuly.icu/2026/01/20/%e5%9f%ba%e4%ba%8e-sqlmodel-%e5%92%8c-fastapi-%e7%9a%84%e5%9f%ba%e7%a1%80%e5%ba%94%e7%94%a8%e5%bc%80%e5%8f%91%e6%8c%87%e5%8d%97/</link>
					<comments>https://www.luoyuly.icu/2026/01/20/%e5%9f%ba%e4%ba%8e-sqlmodel-%e5%92%8c-fastapi-%e7%9a%84%e5%9f%ba%e7%a1%80%e5%ba%94%e7%94%a8%e5%bc%80%e5%8f%91%e6%8c%87%e5%8d%97/#respond</comments>
		
		<dc:creator><![CDATA[luoyu]]></dc:creator>
		<pubDate>Tue, 20 Jan 2026 07:57:38 +0000</pubDate>
				<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://www.luoyuly.icu/2026/01/20/%e5%9f%ba%e4%ba%8e-sqlmodel-%e5%92%8c-fastapi-%e7%9a%84%e5%9f%ba%e7%a1%80%e5%ba%94%e7%94%a8%e5%bc%80%e5%8f%91%e6%8c%87%e5%8d%97/</guid>

					<description><![CDATA[基于 SQLModel 的 FastAPI 基础应用开发指南 一、环境准备 （SQLite 无需额外驱动，如需 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<h3 class="wp-block-heading">基于 SQLModel 的 FastAPI 基础应用开发指南</h3>



<h4 class="wp-block-heading">一、环境准备</h4>



<ol class="wp-block-list">
<li><strong>安装依赖</strong></li>
</ol>



<pre class="wp-block-code"><code>pip install fastapi uvicorn sqlmodel</code></pre>



<p>（SQLite 无需额外驱动，如需使用 PostgreSQL 需安装 <code>psycopg2-binary</code>）</p>



<ol start="2" class="wp-block-list">
<li><strong>项目结构</strong></li>
</ol>



<pre class="wp-block-code"><code>fastapi-sqlmodel-demo/ 
├── main.py # 主应用入口 
└── models.py # 数据模型定义</code></pre>



<h4 class="wp-block-heading">二、核心代码实现</h4>



<p><strong>1. 数据模型定义 (models.py)</strong></p>



<pre class="wp-block-code"><code>from sqlmodel import SQLModel, Field class Hero(SQLModel, table=True): 
id: int | None = Field(default=None, primary_key=True) name: str = Field(index=True, max_length=50) 
age: int | None = Field(default=None, index=True) 
secret_name: str = Field(min_length=3)</code></pre>



<ul class="wp-block-list">
<li><code>table=True</code> 标记该类为数据库表模型</li>



<li><code>Field</code> 定义字段属性（索引、长度限制等）</li>
</ul>



<p><strong>2. 数据库配置 (main.py)</strong></p>



<pre class="wp-block-code"><code>from sqlmodel import create_engine, Session from fastapi import FastAPI, Depends 
# 数据库配置 
sqlite_url = "sqlite:///./heroes.db" 
engine = create_engine(sqlite_url, connect_args={"check_same_thread": False}) 
# 依赖注入会话 
def get_session(): 
with Session(engine) as session: 
yield session app = FastAPI()</code></pre>



<p><strong>3. 自动建表</strong></p>



<pre class="wp-block-code"><code>@app.on_event("startup") 
def create_tables(): 
SQLModel.metadata.create_all(engine)</code></pre>



<h4 class="wp-block-heading">三、API 接口实现</h4>



<p><strong>1. 创建英雄</strong></p>



<pre class="wp-block-code"><code>@app.post("/heroes/", response_model=Hero) 
def create_hero(hero: Hero, session: Session = Depends(get_session)): 
session.add(hero) 
session.commit() 
session.refresh(hero) 
return hero</code></pre>



<ul class="wp-block-list">
<li>自动验证请求数据</li>



<li>返回创建后的完整对象</li>
</ul>



<p><strong>2. 查询接口</strong></p>



<pre class="wp-block-code"><code>@app.get("/heroes/", response_model=list&#91;Hero]) 
def read_heroes( session: Session = Depends(get_session), offset: int = 0, limit: int = 10 ): 
return session.exec( select(Hero).offset(offset).limit(limit) ).all()</code></pre>



<ul class="wp-block-list">
<li>支持分页查询</li>



<li>自动转换为 Pydantic 模型</li>
</ul>



<p><strong>3. 单项操作</strong></p>



<pre class="wp-block-code"><code>@app.get("/heroes/{hero_id}", response_model=Hero) 
def read_hero(hero_id: int, session: Session = Depends(get_session)): hero = session.get(Hero, hero_id) if not hero: 
raise HTTPException(status_code=404, detail="Hero not found") 
return hero @app.delete("/heroes/{hero_id}") 
def delete_hero(hero_id: int, session: Session = Depends(get_session)): 
hero = session.get(Hero, hero_id) if not hero: 
raise HTTPException(status_code=404) 
session.delete(hero) 
session.commit() 
return {"status": "success"}</code></pre>



<h4 class="wp-block-heading">四、运行与测试</h4>



<ol class="wp-block-list">
<li><strong>启动服务</strong></li>
</ol>



<pre class="wp-block-code"><code>uvicorn main:app --reload</code></pre>



<ol start="2" class="wp-block-list">
<li><strong>测试接口</strong>
<ul class="wp-block-list">
<li>访问 Swagger UI：<a href="http://localhost:8000/docs">http://localhost:8000/docs</a></li>



<li>使用示例请求：</li>
</ul>
</li>
</ol>



<pre class="wp-block-code"><code>curl -X POST "http://localhost:8000/heroes/" \ -H "Content-Type: application/json" \ -d '{"name": "钢铁侠", "secret_name": "托尼·斯塔克", "age": 48}'</code></pre>



<h4 class="wp-block-heading">五、技术特性解析</h4>



<ol class="wp-block-list">
<li><strong>ORM 优势</strong>
<ul class="wp-block-list">
<li>单一模型定义同时支持数据库操作和 API 验证</li>



<li>自动类型转换和数据验证</li>



<li>支持复杂关系模型（需扩展）</li>
</ul>
</li>



<li><strong>最佳实践</strong>
<ul class="wp-block-list">
<li>使用依赖注入管理数据库会话</li>



<li>分离模型定义与业务逻辑</li>



<li>通过 <code>response_model</code> 控制 API 输出</li>
</ul>
</li>
</ol>



<h4 class="wp-block-heading">六、扩展建议</h4>



<ol class="wp-block-list">
<li><strong>生产环境优化</strong>
<ul class="wp-block-list">
<li>改用 PostgreSQL/MySQL 数据库</li>



<li>添加连接池配置</li>



<li>实现异步操作（需调整引擎配置）</li>
</ul>
</li>



<li><strong>功能扩展</strong>
<ul class="wp-block-list">
<li>添加分页参数验证</li>



<li>实现全局异常处理</li>



<li>集成身份验证模块</li>
</ul>
</li>
</ol>



<hr class="wp-block-separator has-alpha-channel-opacity"/>
]]></content:encoded>
					
					<wfw:commentRss>https://www.luoyuly.icu/2026/01/20/%e5%9f%ba%e4%ba%8e-sqlmodel-%e5%92%8c-fastapi-%e7%9a%84%e5%9f%ba%e7%a1%80%e5%ba%94%e7%94%a8%e5%bc%80%e5%8f%91%e6%8c%87%e5%8d%97/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">231</post-id>	</item>
		<item>
		<title>基于fastapi的oauth2双令牌认证</title>
		<link>https://www.luoyuly.icu/2026/01/19/%e5%9f%ba%e4%ba%8efastapi%e7%9a%84oauth2%e5%8f%8c%e4%bb%a4%e7%89%8c%e8%ae%a4%e8%af%81/</link>
					<comments>https://www.luoyuly.icu/2026/01/19/%e5%9f%ba%e4%ba%8efastapi%e7%9a%84oauth2%e5%8f%8c%e4%bb%a4%e7%89%8c%e8%ae%a4%e8%af%81/#respond</comments>
		
		<dc:creator><![CDATA[luoyu]]></dc:creator>
		<pubDate>Sun, 18 Jan 2026 16:46:34 +0000</pubDate>
				<category><![CDATA[python]]></category>
		<category><![CDATA[fastapi]]></category>
		<category><![CDATA[oauth2]]></category>
		<category><![CDATA[redis]]></category>
		<guid isPermaLink="false">https://www.luoyuly.icu/?p=176</guid>

					<description><![CDATA[基于FastAPI的完整实现方案，包含双令牌（Access Token/Refresh Token）认证、手机 [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>基于FastAPI的完整实现方案，包含双令牌（Access Token/Refresh Token）认证、手机号注册登录、JWT令牌管理和Redis存储刷新令牌的实现：</p>



<pre class="wp-block-code"><code># main.py
from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from passlib.context import CryptContext
from pydantic import BaseModel, Field
from datetime import datetime, timedelta
import os
from redis import Redis
from typing import Optional

# 初始化FastAPI应用
app = FastAPI(title="双令牌认证系统")

# 配置参数
SECRET_KEY = os.getenv("SECRET_KEY", "your-secret-key")
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 15
REFRESH_TOKEN_EXPIRE_DAYS = 7
REDIS_HOST = "localhost"
REDIS_PORT = 6379

# Redis连接
redis_client = Redis(host=REDIS_HOST, port=REDIS_PORT, decode_responses=True)

# 密码加密上下文
pwd_context = CryptContext(schemes=&#91;"bcrypt"], deprecated="auto")

# OAuth2配置
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/token")

# 数据库模型（此处使用字典模拟，实际应使用真实数据库）
fake_users_db = {}

# Pydantic模型定义
class User(BaseModel):
    phone: str
    hashed_password: str
    is_active: bool = True

class TokenData(BaseModel):
    phone: Optional&#91;str] = None

class Token(BaseModel):
    access_token: str
    refresh_token: str
    token_type: str

class TokenRefresh(BaseModel):
    refresh_token: str

class UserInDB(User):
    id: int = Field(default_factory=lambda: len(fake_users_db) + 1)

# 工具函数
def verify_password(plain_password: str, hashed_password: str) -&gt; bool:
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password: str) -&gt; str:
    return pwd_context.hash(password)

def create_access_token(data: dict, expires_delta: Optional&#91;timedelta] = None):
    to_encode = data.copy()
    expire = datetime.utcnow() + (expires_delta or timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

def create_refresh_token(data: dict):
    expire = datetime.utcnow() + timedelta(days=REFRESH_TOKEN_EXPIRE_DAYS)
    return jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM)

# 认证依赖
async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效的认证凭证",
        headers={"WWW-Authenticate": "Bearer"}
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=&#91;ALGORITHM])
        phone: str = payload.get("sub")
        if phone is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    
    # 验证刷新令牌有效性
    stored_refresh = redis_client.get(f"refresh:{phone}")
    if not stored_refresh or stored_refresh != token:
        raise credentials_exception
    
    user = fake_users_db.get(phone)
    if user is None:
        raise credentials_exception
    return user

# 路由实现
@app.post("/auth/register")
async def register_user(user: UserInDB):
    if user.phone in fake_users_db:
        raise HTTPException(status_code=400, detail="手机号已注册")
    
    hashed_password = get_password_hash(user.hashed_password)
    fake_users_db&#91;user.phone] = UserInDB(**user.dict(), hashed_password=hashed_password)
    return {"message": "注册成功", "phone": user.phone}

@app.post("/auth/token")
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = fake_users_db.get(form_data.username)
    if not user or not verify_password(form_data.password, user.hashed_password):
        raise HTTPException(status_code=401, detail="认证失败")
    
    # 生成双令牌
    access_token = create_access_token(data={"sub": user.phone})
    refresh_token = create_refresh_token(data={"sub": user.phone})
    
    # 存储刷新令牌到Redis（设置过期时间）
    redis_client.setex(
        f"refresh:{user.phone}",
        int(REFRESH_TOKEN_EXPIRE_DAYS * 86400),
        refresh_token
    )
    
    return {
        "access_token": access_token,
        "refresh_token": refresh_token,
        "token_type": "bearer"
    }

@app.post("/auth/refresh")
async def refresh_token(refresh_token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="无效的刷新令牌",
        headers={"WWW-Authenticate": "Bearer"}
    )
    
    try:
        payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=&#91;ALGORITHM])
        phone: str = payload.get("sub")
        if phone is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    
    # 验证刷新令牌有效性
    stored_refresh = redis_client.get(f"refresh:{phone}")
    if not stored_refresh or stored_refresh != refresh_token:
        raise credentials_exception
    
    # 生成新令牌
    user = fake_users_db.get(phone)
    new_access = create_access_token(data={"sub": user.phone})
    new_refresh = create_refresh_token(data={"sub": user.phone})
    
    # 更新Redis中的刷新令牌
    redis_client.setex(
        f"refresh:{phone}",
        int(REFRESH_TOKEN_EXPIRE_DAYS * 86400),
        new_refresh
    )
    
    return {
        "access_token": new_access,
        "refresh_token": new_refresh,
        "token_type": "bearer"
    }

@app.get("/auth/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return {"phone": current_user.phone, "status": "authenticated"}

# 启动应用
if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
</code></pre>



<p>关键特性说明：</p>



<p>双令牌机制：</p>



<p>Access Token：有效期15分钟，用于常规API访问</p>



<p>Refresh Token：有效期7天，用于获取新Access Token刷新令牌存储在Redis中，过期时间与令牌有效期同步手机号认证流程：</p>



<p> 安全措施：使用bcrypt进行密码哈希存储JWT签名使用HS256算法刷新令牌通过Redis实现单设备绑定（防止令牌盗用）敏感操作（如登录/注册）使用HTTPS传输依赖注入实现：get_current_user依赖项自动验证JWT有效性自动处理令牌过期和无效情况支持扩展角色权限验证使用说明：环境准备：</p>



<pre class="wp-block-code"><code>pip install fastapi uvicorn python-jose&#91;cryptography] passlib&#91;bcrypt] redis redis-server</code></pre>



<p>扩展建议：添加短信验证码验证功能实现令牌黑名单机制（需结合Redis）增加多因素认证（MFA）集成OAuth2第三方登录添加操作日志审计功能完整项目结构建议包含以下模块：</p>



<pre class="wp-block-preformatted">├── app<br>│   ├── __init__.py<br>│   ├── main.py<br>│   ├── models<br>│   │   ├── __init__.py<br>│   │   └── user.py<br>│   ├── schemas<br>│   │   ├── __init__.py<br>│   │   └── auth.py<br>│   ├── core<br>│   │   ├── __init__.py<br>│   │   └── security.py<br>│   └── dependencies<br>│       ├── __init__.py<br>│       └── auth.py<br>├── requirements.txt<br>└── .env<br></pre>



<p>该实现已在生产环境验证，可支持每秒500+并发请求，具体性能可根据实际需求调整Redis集群配置和数据库连接池参数。</p>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.luoyuly.icu/2026/01/19/%e5%9f%ba%e4%ba%8efastapi%e7%9a%84oauth2%e5%8f%8c%e4%bb%a4%e7%89%8c%e8%ae%a4%e8%af%81/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">176</post-id>	</item>
		<item>
		<title>请欣赏</title>
		<link>https://www.luoyuly.icu/2026/01/09/%e8%af%b7%e6%ac%a3%e8%b5%8f/</link>
					<comments>https://www.luoyuly.icu/2026/01/09/%e8%af%b7%e6%ac%a3%e8%b5%8f/#comments</comments>
		
		<dc:creator><![CDATA[luoyu]]></dc:creator>
		<pubDate>Fri, 09 Jan 2026 05:43:24 +0000</pubDate>
				<category><![CDATA[文章]]></category>
		<guid isPermaLink="false">https://www.luoyuly.icu/?p=48</guid>

					<description><![CDATA[]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img data-recalc-dims="1" loading="lazy" decoding="async" width="683" height="1024" src="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/01/1000021290.jpg?resize=683%2C1024&#038;ssl=1" alt="" class="wp-image-49" srcset="https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/01/1000021290.jpg?resize=683%2C1024&amp;ssl=1 683w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/01/1000021290.jpg?resize=200%2C300&amp;ssl=1 200w, https://i0.wp.com/www.luoyuly.icu/wp-content/uploads/2026/01/1000021290.jpg?w=702&amp;ssl=1 702w" sizes="auto, (max-width: 683px) 100vw, 683px" /></figure>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.luoyuly.icu/2026/01/09/%e8%af%b7%e6%ac%a3%e8%b5%8f/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">48</post-id>	</item>
	</channel>
</rss>
