Files
ai-app-database/app/routes/auth.py
T
huty f3bd3f68a5
CI — Docker Build & Push / Build & Push Image (push) Failing after 10m15s
新增文件夹功能
2026-04-23 15:45:28 +09:00

140 lines
5.5 KiB
Python

from datetime import datetime
from flask import (Blueprint, render_template, redirect, url_for,
flash, request, session)
from flask_login import login_user, logout_user, login_required, current_user
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Email, Length, EqualTo, ValidationError
from app.extensions import db, bcrypt
from app.models.user import User
from app.models.setting import SystemSetting
auth_bp = Blueprint('auth', __name__)
# ── 表单定义 ──────────────────────────────────────────────────────────────────
class LoginForm(FlaskForm):
username = StringField('用户名', validators=[DataRequired(message='请输入用户名')])
password = PasswordField('密码', validators=[DataRequired(message='请输入密码')])
remember = BooleanField('记住我')
submit = SubmitField('登录')
class RegisterForm(FlaskForm):
username = StringField('用户名', validators=[
DataRequired(), Length(min=3, max=64, message='用户名长度 3-64 位')
])
email = StringField('邮箱', validators=[
DataRequired(), Email(message='请输入有效的邮箱地址')
])
password = PasswordField('密码', validators=[
DataRequired(), Length(min=8, message='密码至少 8 位')
])
password2 = PasswordField('确认密码', validators=[
DataRequired(), EqualTo('password', message='两次密码不一致')
])
submit = SubmitField('注册')
def validate_username(self, field):
if User.query.filter_by(username=field.data).first():
raise ValidationError('用户名已被使用')
def validate_email(self, field):
if User.query.filter_by(email=field.data).first():
raise ValidationError('邮箱已被注册')
class ChangePasswordForm(FlaskForm):
old_password = PasswordField('当前密码', validators=[DataRequired()])
new_password = PasswordField('新密码', validators=[
DataRequired(), Length(min=8, message='密码至少 8 位')
])
new_password2 = PasswordField('确认新密码', validators=[
DataRequired(), EqualTo('new_password', message='两次密码不一致')
])
submit = SubmitField('修改密码')
# ── 路由 ──────────────────────────────────────────────────────────────────────
@auth_bp.route('/login', methods=['GET', 'POST'])
def login():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
form = LoginForm()
if form.validate_on_submit():
user = User.query.filter_by(username=form.username.data).first()
if user and bcrypt.check_password_hash(user.password_hash, form.password.data):
if not user.is_active:
flash('账号已被禁用,请联系管理员', 'danger')
return render_template('auth/login.html', form=form)
login_user(user, remember=form.remember.data)
user.last_login = datetime.utcnow()
db.session.commit()
# 安全重定向
next_page = request.args.get('next')
if next_page and next_page.startswith('/'):
return redirect(next_page)
return redirect(url_for('main.index'))
else:
flash('用户名或密码错误', 'danger')
allow_register = SystemSetting.get('allow_register', 'true') == 'true'
return render_template('auth/login.html', form=form, allow_register=allow_register)
@auth_bp.route('/logout', methods=['POST'])
@login_required
def logout():
logout_user()
flash('已安全退出', 'success')
return redirect(url_for('auth.login'))
@auth_bp.route('/register', methods=['GET', 'POST'])
def register():
if current_user.is_authenticated:
return redirect(url_for('main.index'))
allow = SystemSetting.get('allow_register', 'true')
if allow != 'true':
flash('系统暂未开放注册,请联系管理员', 'warning')
return redirect(url_for('auth.login'))
form = RegisterForm()
if form.validate_on_submit():
pw_hash = bcrypt.generate_password_hash(form.password.data).decode('utf-8')
user = User(
username=form.username.data,
email=form.email.data,
password_hash=pw_hash,
role='user'
)
db.session.add(user)
db.session.commit()
flash('注册成功,请登录', 'success')
return redirect(url_for('auth.login'))
return render_template('auth/register.html', form=form)
@auth_bp.route('/change-password', methods=['GET', 'POST'])
@login_required
def change_password():
form = ChangePasswordForm()
if form.validate_on_submit():
if not bcrypt.check_password_hash(current_user.password_hash,
form.old_password.data):
flash('当前密码错误', 'danger')
else:
current_user.password_hash = bcrypt.generate_password_hash(
form.new_password.data
).decode('utf-8')
db.session.commit()
flash('密码修改成功', 'success')
return redirect(url_for('main.index'))
return render_template('auth/change_password.html', form=form)