Day2-数据验证增强

昨天搭了个基本的博客API,但数据验证太简单了。今天加强一下验证规则,让系统更安全。

昨天的问题

Day1的验证确实太弱了:

  • 密码只检查长度,"12345678"这种弱密码也能过
  • 邮箱没限制域名,临时邮箱、垃圾邮箱都能注册
  • 文章内容没过滤,啥都能发

今天分三步解决:密码强度 → 邮箱限制 → 内容过滤

第一步:密码强度验证

昨天只检查密码长度,"12345678"这种弱密码也能过。现在加上复杂度要求。

修改密码验证

在Day1代码基础上,只改schemas.py里的密码验证:

# 修改 schemas.py 中的 UserRegister 类
# 其他代码保持不变,只增加密码复杂度检查

from pydantic import BaseModel, Field, EmailStr, validator
import re

class UserRegister(BaseModel):
    """用户注册模型"""
    username: str = Field(..., min_length=3, max_length=50, description="用户名")
    email: EmailStr = Field(..., description="邮箱地址")
    password: str = Field(..., min_length=8, description="密码")
    
    # 新增:密码复杂度验证
    @validator('password')
    def validate_password_strength(cls, v):
        """验证密码强度"""
        # 检查大写字母
        if not re.search(r'[A-Z]', v):
            raise ValueError('密码必须包含至少一个大写字母')
        
        # 检查小写字母
        if not re.search(r'[a-z]', v):
            raise ValueError('密码必须包含至少一个小写字母')
        
        # 检查数字
        if not re.search(r'\d', v):
            raise ValueError('密码必须包含至少一个数字')
        
        # 检查特殊字符
        if not re.search(r'[!@#$%^&*(),.?":{}|<>]', v):
            raise ValueError('密码必须包含至少一个特殊字符(!@#$%^&*等)')
        
        # 检查连续字符(防止123456、abcdef这类密码)
        if re.search(r'(.)\1{2,}', v):  # 3个以上相同字符
            raise ValueError('密码不能包含3个以上连续相同字符')
        
        if re.search(r'(012|123|234|345|456|567|678|789)', v):
            raise ValueError('密码不能包含连续数字')
            
        if re.search(r'(abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz)', v.lower()):
            raise ValueError('密码不能包含连续字母')
        
        return v

测试密码验证

测试弱密码(应该失败):

curl -X POST "http://localhost:8000/users/register" \
     -H "Content-Type: application/json" \
     -d '{
       "username": "洛克斯", 
       "email": "luokesi@example.com",
       "password": "12345678"
     }'

应该会看到详细的错误信息:

在这里插入图片描述

测试强密码(应该成功):

curl -X POST "http://localhost:8000/users/register" \
     -H "Content-Type: application/json" \
     -d '{
       "username": "洛克斯", 
       "email": "luokesi@example.com",
       "password": "MyPass136!"
     }'

在这里插入图片描述


第二步:邮箱域名限制

有用户用临时邮箱注册,过期后找不回账号。还有垃圾邮箱增加运营成本。限制一下邮箱域名。

增加邮箱域名验证

在第一步基础上,继续修改schemas.py:

# 修改 schemas.py 中的 UserRegister 类
# 其他代码保持不变,只增加邮箱域名验证

from pydantic import BaseModel, Field, EmailStr, validator
import re

class UserRegister(BaseModel):
    """用户注册模型 - 负责格式验证"""
    username: str = Field(..., min_length=3, max_length=50, description="用户名")
    email: EmailStr = Field(..., description="邮箱地址")
    password: str = Field(..., min_length=8, description="密码")
    
    @validator('password')
    def validate_password_strength(cls, v):
        """验证密码强度"""
        # 检查大写字母
        if not re.search(r'[A-Z]', v):
            raise ValueError('密码必须包含至少一个大写字母')
        
        # 检查小写字母
        if not re.search(r'[a-z]', v):
            raise ValueError('密码必须包含至少一个小写字母')
        
        # 检查数字
        if not re.search(r'\d', v):
            raise ValueError('密码必须包含至少一个数字')
        
        # 检查特殊字符
        if not re.search(r'[!@#$%^&*(),.?":{}|<>]', v):
            raise ValueError('密码必须包含至少一个特殊字符(!@#$%^&*等)')
        
        # 检查连续字符(防止123456、abcdef这类密码)
        if re.search(r'(.)\1{2,}', v):  # 3个以上相同字符
            raise ValueError('密码不能包含3个以上连续相同字符')
        
        if re.search(r'(012|123|234|345|456|567|678|789)', v):
            raise ValueError('密码不能包含连续数字')
            
        if re.search(r'(abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz)', v.lower()):
            raise ValueError('密码不能包含连续字母')
        
        return v
    
    # 新增:邮箱域名验证
    @validator('email')
    def validate_email_domain(cls, v):
        """验证邮箱域名限制"""
        domain = v.split('@')[1].lower()
        allowed_domains = [
            'gmail.com', 'qq.com', '163.com', '126.com',
            'outlook.com', 'hotmail.com', 'sina.com'
        ]
        
        if domain not in allowed_domains:
            allowed_list = ', '.join(allowed_domains)
            raise ValueError(f'不支持的邮箱域名,请使用以下邮箱: {allowed_list}')
        
        return v

测试邮箱域名限制

测试不支持的邮箱域名(应该失败):

curl -X POST "http://localhost:8000/users/register" \
     -H "Content-Type: application/json" \
     -d '{
       "username": "我是罗杰",
       "email": "luojie@onepiece.com",
       "password": "MyPass136!"
     }'

应该看到域名限制的错误:

在这里插入图片描述

测试支持的邮箱域名(应该成功):

curl -X POST "http://localhost:8000/users/register" \
     -H "Content-Type: application/json" \
     -d '{
       "username": "我是罗杰",
       "email": "luojie@qq.com",
       "password": "MyPass136!"
     }'

在这里插入图片描述


第三步:内容安全过滤

用户发文章可能包含广告、垃圾信息。加个基础的内容检查。

增加内容安全验证

添加内容安全检查函数,在文章创建时使用:

# 继续修改 schemas.py
# 在文件开头增加内容安全检查函数

def validate_content_safety(content: str) -> str:
    """检查内容安全性"""
    # 定义敏感词列表(实际项目中应该从数据库或配置文件读取)
    banned_words = [
        '黑胡子','白胡子','茶胡子'
    ]
    
    content_lower = content.lower()
    for banned_word in banned_words:
        if banned_word in content_lower:
            raise ValueError(f'内容中包含敏感词: {banned_word}')
    
    return content

# 修改 PostCreate 模型,增加内容安全检查
class PostCreate(BaseModel):
    """文章创建模型"""
    title: str = Field(..., min_length=5, max_length=200, description="文章标题")
    content: str = Field(..., min_length=10, description="文章内容")
    
    # 新增:文章标题安全检查
    @validator('title')
    def validate_title_safety(cls, v):
        """验证文章标题安全性"""
        return validate_content_safety(v)
    
    # 新增:文章内容安全检查
    @validator('content')
    def validate_content_safety_and_length(cls, v):
        """验证文章内容安全性和长度"""
        # 检查内容安全
        validate_content_safety(v)
        
        # 检查内容长度上限
        if len(v) > 10000:
            raise ValueError('文章内容不能超过10000字符')
        
        return v

测试内容过滤

注意:发布文章需要先登录

# 首先确保已登录(如果还没登录的话)
curl -X POST "http://localhost:8000/users/login" \
     -H "Content-Type: application/json" \
     -d '{
       "account": "我是罗杰",
       "password": "MyPass136!"
     }'

在这里插入图片描述

然后测试包含敏感词的文章(应该失败):

curl -X POST "http://localhost:8000/posts" \
     -H "Content-Type: application/json" \
     -d '{
       "title": "他们都是胡子",
       "content": "白胡子强于黑胡子,黑胡子强于茶胡子!"
     }'

现在应该会看到内容安全验证的错误信息
在这里插入图片描述


更新版本信息

完成验证功能后,更新main.py中的版本信息:

修改的地方

# 1. 更新应用标题和版本
app = FastAPI(
    title="博客系统API v2.0",  # 从 "博客系统API" 改为 "博客系统API v2.0"
    description="7天FastAPI学习系列 - Day2数据验证增强版本",  # 更新描述
    version="2.0.0"  # 从 "1.0.0" 改为 "2.0.0"
)

# 2. 更新根路由的版本信息
@app.get("/")
def root():
    return {
        "message": "欢迎使用博客系统API v2.0",  # 更新消息
        "version": "2.0.0",  # 更新版本号
        "docs": "/docs",
        "features": ["用户管理", "文章管理", "数据验证增强"],  # 添加新功能
        "next_version": "Day3将添加数据库持久化"  # 更新下一步
    }

# 3. 更新健康检查接口
@app.get("/health")
def health_check():
    return {
        "status": "healthy",
        "version": "2.0.0",  # 添加版本信息
        "users_count": len(users_db),
        "posts_count": len(posts_db)
    }

今天完成了什么

加强了数据验证:

  • 密码强度:大小写字母 + 数字 + 特殊字符
  • 邮箱限制:只允许主流邮箱域名
  • 内容过滤:基础的敏感词检查

现在的系统安全性提升了不少,但还是用内存存储。明天换成真正的数据库。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值