You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flask模型中存储登录用手机号字段的最佳实践(附Django参考)

Flask中手机号登录的最佳实践

1. 数据库层:手机号字段设计与校验

Flask没有内置的PhoneNumberField,可以通过SQLAlchemy结合第三方库实现类似Django的手机号约束与验证:

from sqlalchemy import Column, String
from your_app import db
import phonenumbers

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    # 手机号字段:唯一约束、非空,长度设为20兼容国际号码
    phone_number = db.Column(String(20), unique=True, nullable=False)
    password_hash = db.Column(String(128))  # 密码哈希存储

    @staticmethod
    def validate_phone_number(phone):
        """校验手机号格式合法性"""
        try:
            parsed_num = phonenumbers.parse(phone, None)
            return phonenumbers.is_valid_number(parsed_num)
        except phonenumbers.NumberParseException:
            return False

2. 基础密码登录实现

核心逻辑:校验手机号格式→查询用户→验证密码→维护登录状态

from flask import request, jsonify, session
from werkzeug.security import check_password_hash
from your_app.models import User

@app.route('/login', methods=['POST'])
def login():
    data = request.get_json()
    phone = data.get('phone_number')
    password = data.get('password')

    # 第一步:校验手机号格式
    if not User.validate_phone_number(phone):
        return jsonify({'error': '无效的手机号格式'}), 400

    # 第二步:查询用户
    user = User.query.filter_by(phone_number=phone).first()
    if not user or not check_password_hash(user.password_hash, password):
        return jsonify({'error': '手机号或密码错误'}), 401

    # 第三步:维护登录状态(示例用session,也可替换为JWT)
    session['user_id'] = user.id

    return jsonify({'message': '登录成功', 'user_id': user.id})

3. 注册环节的手机号校验

注册时提前拦截非法手机号与重复注册:

from werkzeug.security import generate_password_hash

@app.route('/register', methods=['POST'])
def register():
    data = request.get_json()
    phone = data.get('phone_number')
    password = data.get('password')

    if not User.validate_phone_number(phone):
        return jsonify({'error': '无效的手机号格式'}), 400

    if User.query.filter_by(phone_number=phone).first():
        return jsonify({'error': '该手机号已注册'}), 409

    # 创建新用户,密码哈希存储
    new_user = User(
        phone_number=phone,
        password_hash=generate_password_hash(password)
    )
    db.session.add(new_user)
    db.session.commit()

    return jsonify({'message': '注册成功'}), 201

4. 更实用的验证码登录实现

手机号登录常用验证码替代密码,需结合缓存(如Redis)存储验证码:

发送验证码接口

import random
import redis
from your_app import redis_client  # 提前初始化Redis连接

@app.route('/send-verification-code', methods=['POST'])
def send_code():
    data = request.get_json()
    phone = data.get('phone_number')

    if not User.validate_phone_number(phone):
        return jsonify({'error': '无效的手机号格式'}), 400

    # 生成6位验证码
    code = str(random.randint(100000, 999999))
    # 存入Redis,设置5分钟过期
    redis_client.setex(f'verify_code:{phone}', 300, code)

    # 此处替换为实际短信/邮件发送逻辑
    # send_sms(phone, f'您的登录验证码是:{code},5分钟内有效')

    return jsonify({'message': '验证码已发送'}), 200

验证码登录接口

@app.route('/login-with-code', methods=['POST'])
def login_with_code():
    data = request.get_json()
    phone = data.get('phone_number')
    code = data.get('code')

    if not User.validate_phone_number(phone):
        return jsonify({'error': '无效的手机号格式'}), 400

    # 校验验证码
    stored_code = redis_client.get(f'verify_code:{phone}')
    if not stored_code or stored_code.decode('utf-8') != code:
        return jsonify({'error': '验证码错误或已过期'}), 401

    # 可选逻辑:手机号未注册则自动创建用户
    user = User.query.filter_by(phone_number=phone).first()
    if not user:
        user = User(phone_number=phone)
        db.session.add(user)
        db.session.commit()

    # 维护登录状态
    session['user_id'] = user.id
    return jsonify({'message': '登录成功', 'user_id': user.id})

5. 安全注意事项

  • 强制使用HTTPS传输手机号、密码、验证码,防止明文泄露
  • 密码必须哈希存储,禁止明文保存
  • 限制验证码发送频率(如1分钟内仅允许发送1次),防止恶意刷接口
  • 验证码设置合理过期时间(5-10分钟),降低被破解风险

内容的提问来源于stack exchange,提问作者Mike D Hovhannisyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 05:10:36