2025-09-15 00:15:37 +08:00

217 lines
8.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from flask import Blueprint, render_template, request, flash, redirect, url_for, jsonify
from flask_login import login_user, logout_user, login_required, current_user
from app.models import User, EmailVerification
from app import db, login_manager
from utils import send_verification_email, send_password_reset_email
import re
auth_bp = Blueprint('auth', __name__)
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@auth_bp.route('/register', methods=['GET', 'POST'])
def register():
"""用户注册"""
if request.method == 'POST':
try:
# 获取表单数据
email = request.form.get('email', '').strip().lower()
password = request.form.get('password', '').strip()
confirm_password = request.form.get('confirm_password', '').strip()
name = request.form.get('name', '').strip()
age = request.form.get('age', '').strip()
gender = request.form.get('gender', '').strip()
parent_contact = request.form.get('parent_contact', '').strip()
verification_code = request.form.get('verification_code', '').strip()
# 验证必填字段
if not all([email, password, confirm_password, name, age, gender, verification_code]):
flash('请填写所有必填字段', 'error')
return render_template('auth/register.html')
# 邮箱格式验证
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(email_pattern, email):
flash('请输入有效的邮箱地址', 'error')
return render_template('auth/register.html')
# 密码验证
if len(password) < 6:
flash('密码长度至少6位', 'error')
return render_template('auth/register.html')
if password != confirm_password:
flash('两次输入的密码不一致', 'error')
return render_template('auth/register.html')
# 验证年龄
try:
age = int(age)
if age < 3 or age > 6:
flash('年龄必须在3-6岁之间', 'error')
return render_template('auth/register.html')
except ValueError:
flash('请输入有效的年龄', 'error')
return render_template('auth/register.html')
# 验证性别
if gender not in ['0', '1']:
flash('请选择性别', 'error')
return render_template('auth/register.html')
# 检查邮箱是否已注册
existing_user = User.query.filter_by(email=email).first()
if existing_user:
flash('该邮箱已被注册', 'error')
return render_template('auth/register.html')
# 验证邮箱验证码
if not EmailVerification.verify_code(email, verification_code):
flash('验证码错误或已过期', 'error')
return render_template('auth/register.html')
# 创建新用户
new_user = User(
email=email,
name=name,
age=age,
gender=int(gender),
parent_contact=parent_contact if parent_contact else None,
is_verified=True # 通过邮箱验证码验证,标记为已验证
)
new_user.set_password(password)
db.session.add(new_user)
db.session.commit()
flash('注册成功!请登录', 'success')
return redirect(url_for('auth.login'))
except Exception as e:
db.session.rollback()
flash('注册失败,请重试', 'error')
return render_template('auth/register.html')
return render_template('auth/register.html')
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
"""用户登录"""
if request.method == 'POST':
email = request.form.get('email', '').strip().lower()
password = request.form.get('password', '').strip()
remember = bool(request.form.get('remember'))
if not email or not password:
flash('请输入邮箱和密码', 'error')
return render_template('auth/login.html')
user = User.query.filter_by(email=email).first()
if user and user.check_password(password):
login_user(user, remember=remember)
flash(f'欢迎回来,{user.name}', 'success')
# 重定向到之前访问的页面,如果没有则到主页
next_page = request.args.get('next')
if next_page:
return redirect(next_page)
return redirect(url_for('main.dashboard'))
else:
flash('邮箱或密码错误', 'error')
return render_template('auth/login.html')
@auth_bp.route('/logout')
@login_required
def logout():
"""用户登出"""
logout_user()
flash('已成功登出', 'success')
return redirect(url_for('main.index'))
@auth_bp.route('/forgot-password', methods=['GET', 'POST'])
def forgot_password():
"""忘记密码"""
if request.method == 'POST':
email = request.form.get('email', '').strip().lower()
verification_code = request.form.get('verification_code', '').strip()
new_password = request.form.get('new_password', '').strip()
confirm_password = request.form.get('confirm_password', '').strip()
# 检查用户是否存在
user = User.query.filter_by(email=email).first()
if not user:
flash('该邮箱未注册', 'error')
return render_template('auth/forgot_password.html')
# 如果是重置密码请求
if verification_code and new_password:
if len(new_password) < 6:
flash('密码长度至少6位', 'error')
return render_template('auth/forgot_password.html')
if new_password != confirm_password:
flash('两次输入的密码不一致', 'error')
return render_template('auth/forgot_password.html')
# 验证验证码
if not EmailVerification.verify_code(email, verification_code):
flash('验证码错误或已过期', 'error')
return render_template('auth/forgot_password.html')
# 更新密码
user.set_password(new_password)
db.session.commit()
flash('密码重置成功,请使用新密码登录', 'success')
return redirect(url_for('auth.login'))
return render_template('auth/forgot_password.html')
@auth_bp.route('/send-verification-code', methods=['POST'])
def send_verification_code():
"""发送邮箱验证码"""
try:
email = request.json.get('email', '').strip().lower()
code_type = request.json.get('type', 'register') # register 或 reset_password
if not email:
return jsonify({'success': False, 'message': '请输入邮箱地址'})
# 邮箱格式验证
email_pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
if not re.match(email_pattern, email):
return jsonify({'success': False, 'message': '请输入有效的邮箱地址'})
# 根据类型检查邮箱
if code_type == 'register':
# 注册时检查邮箱是否已存在
existing_user = User.query.filter_by(email=email).first()
if existing_user:
return jsonify({'success': False, 'message': '该邮箱已被注册'})
elif code_type == 'reset_password':
# 重置密码时检查邮箱是否存在
existing_user = User.query.filter_by(email=email).first()
if not existing_user:
return jsonify({'success': False, 'message': '该邮箱未注册'})
# 生成验证码
verification_code = EmailVerification.generate_code(email, expire_minutes=5)
# 发送邮件
if code_type == 'register':
success = send_verification_email(email, verification_code)
else:
success = send_password_reset_email(email, verification_code)
if success:
return jsonify({'success': True, 'message': '验证码已发送到您的邮箱5分钟内有效'})
else:
return jsonify({'success': False, 'message': '验证码发送失败,请重试'})
except Exception as e:
return jsonify({'success': False, 'message': '发送失败,请重试'})