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
相关产品推荐
相关产品推荐

