217 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
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': '发送失败,请重试'})
 |