登陆注册与忘记密码前后端与jwt配置
Change-Id: Ide4ca3ea34609fdb33ea027e28169852fa41784a
diff --git a/rhj/backend/app/routes.py b/rhj/backend/app/routes.py
new file mode 100644
index 0000000..23ff49b
--- /dev/null
+++ b/rhj/backend/app/routes.py
@@ -0,0 +1,325 @@
+from flask import Blueprint, request, jsonify
+from .functions.FAuth import FAuth
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+from config import Config
+from functools import wraps
+from datetime import datetime
+
+main = Blueprint('main', __name__)
+
+def token_required(f):
+ """装饰器:需要令牌验证"""
+ @wraps(f)
+ def decorated(*args, **kwargs):
+ token = request.headers.get('Authorization')
+ if not token:
+ return jsonify({'success': False, 'message': '缺少访问令牌'}), 401
+
+ session = None
+ try:
+ # 移除Bearer前缀
+ if token.startswith('Bearer '):
+ token = token[7:]
+
+ engine = create_engine(Config.SQLURL)
+ SessionLocal = sessionmaker(bind=engine)
+ session = SessionLocal()
+ f_auth = FAuth(session)
+
+ user = f_auth.get_user_by_token(token)
+ if not user:
+ return jsonify({'success': False, 'message': '无效的访问令牌'}), 401
+
+ # 将用户信息传递给路由函数
+ return f(user, *args, **kwargs)
+ except Exception as e:
+ if session:
+ session.rollback()
+ return jsonify({'success': False, 'message': '令牌验证失败'}), 401
+ finally:
+ if session:
+ session.close()
+
+ return decorated
+
+@main.route('/login', methods=['POST'])
+def login():
+ """用户登录接口"""
+ session = None
+ try:
+ data = request.get_json()
+
+ # 验证必填字段
+ if not data or not data.get('email') or not data.get('password'):
+ return jsonify({
+ 'success': False,
+ 'message': '用户名和密码不能为空'
+ }), 400
+
+ email = data['email']
+ password = data['password']
+
+ # 创建数据库连接
+ engine = create_engine(Config.SQLURL)
+ SessionLocal = sessionmaker(bind=engine)
+ session = SessionLocal()
+
+ # 执行登录
+ f_auth = FAuth(session)
+ result = f_auth.login(email, password)
+
+ if result['success']:
+ session.commit()
+ return jsonify(result), 200
+ else:
+ return jsonify(result), 401
+
+ except Exception as e:
+ if session:
+ session.rollback()
+ return jsonify({
+ 'success': False,
+ 'message': '服务器内部错误'
+ }), 500
+ finally:
+ if session:
+ session.close()
+
+@main.route('/register', methods=['POST'])
+def register():
+ """用户注册接口"""
+
+ engine = create_engine(Config.SQLURL)
+ SessionLocal = sessionmaker(bind=engine)
+ session = SessionLocal()
+
+ try:
+ data = request.get_json()
+
+ # 验证必填字段
+ if not data or not data.get('username') or not data.get('email') or not data.get('password') or not data.get('verification_code'):
+ return jsonify({
+ 'success': False,
+ 'message': '用户名、邮箱和密码不能为空'
+ }), 400
+
+ username = data['username']
+ email = data['email']
+ password = data['password']
+ verification_code = data['verification_code']
+
+ # 简单的邮箱格式验证
+ if '@' not in email or '.' not in email:
+ return jsonify({
+ 'success': False,
+ 'message': '邮箱格式不正确'
+ }), 400
+
+ # 密码长度验证
+ if len(password) < 6:
+ return jsonify({
+ 'success': False,
+ 'message': '密码长度不能少于6位'
+ }), 400
+
+ # 执行注册
+ f_auth = FAuth(session)
+ result = f_auth.register(username, email, password, verification_code)
+
+ if result['success']:
+ session.commit()
+ return jsonify(result), 201
+ else:
+ return jsonify(result), 400
+
+ except Exception as e:
+ session.rollback()
+ return jsonify({
+ 'success': False,
+ 'message': '服务器内部错误'
+ }), 500
+ finally:
+ session.close()
+
+@main.route('/profile', methods=['GET'])
+@token_required
+def get_profile(current_user):
+ """获取用户信息接口(需要登录)"""
+ try:
+ return jsonify({
+ 'success': True,
+ 'user': current_user.to_dict()
+ }), 200
+ except Exception as e:
+ return jsonify({
+ 'success': False,
+ 'message': '获取用户信息失败'
+ }), 500
+
+@main.route('/logout', methods=['POST'])
+@token_required
+def logout(current_user):
+ """用户登出接口(需要登录)"""
+ try:
+ # 这里可以将令牌加入黑名单(如果需要的话)
+ return jsonify({
+ 'success': True,
+ 'message': '登出成功'
+ }), 200
+ except Exception as e:
+ return jsonify({
+ 'success': False,
+ 'message': '登出失败'
+ }), 500
+
+@main.route('/send-verification-code', methods=['POST'])
+def send_verification_code():
+ """发送邮箱验证码接口"""
+
+ engine = create_engine(Config.SQLURL)
+ SessionLocal = sessionmaker(bind=engine)
+ session = SessionLocal()
+
+ try:
+ data = request.get_json()
+
+ # 验证必填字段
+ if not data or not data.get('email'):
+ return jsonify({
+ 'success': False,
+ 'message': '邮箱地址不能为空'
+ }), 400
+
+ email = data['email']
+ verification_type = data.get('type', 'register') # 默认为注册验证码
+
+ # 简单的邮箱格式验证
+ if '@' not in email or '.' not in email:
+ return jsonify({
+ 'success': False,
+ 'message': '邮箱格式不正确'
+ }), 400
+
+ # 发送验证码
+ f_auth = FAuth(session)
+ result = f_auth.send_verification_email(email, verification_type)
+
+ if result['success']:
+ session.commit()
+ return jsonify(result), 200
+ else:
+ return jsonify(result), 400
+
+ except Exception as e:
+ session.rollback()
+ return jsonify({
+ 'success': False,
+ 'message': '服务器内部错误'
+ }), 500
+ finally:
+ session.close()
+
+@main.route('/reset-password', methods=['POST'])
+def reset_password():
+ """重置密码接口"""
+
+ engine = create_engine(Config.SQLURL)
+ SessionLocal = sessionmaker(bind=engine)
+ session = SessionLocal()
+
+ try:
+ data = request.get_json()
+
+ # 验证必填字段
+ if not data or not data.get('email') or not data.get('new_password') or not data.get('verification_code'):
+ return jsonify({
+ 'success': False,
+ 'message': '邮箱地址、新密码和验证码不能为空'
+ }), 400
+
+ email = data['email']
+ new_password = data['new_password']
+ verification_code = data['verification_code']
+
+ # 简单的邮箱格式验证
+ if '@' not in email or '.' not in email:
+ return jsonify({
+ 'success': False,
+ 'message': '邮箱格式不正确'
+ }), 400
+
+ # 密码长度验证
+ if len(new_password) < 6:
+ return jsonify({
+ 'success': False,
+ 'message': '密码长度不能少于6位'
+ }), 400
+
+ # 重置密码
+ f_auth = FAuth(session)
+ result = f_auth.reset_password_with_verification(email, new_password, verification_code)
+
+ if result['success']:
+ session.commit()
+ return jsonify(result), 200
+ else:
+ return jsonify(result), 400
+
+ except Exception as e:
+ session.rollback()
+ return jsonify({
+ 'success': False,
+ 'message': '服务器内部错误'
+ }), 500
+ finally:
+ session.close()
+
+@main.route('/test-jwt', methods=['POST'])
+@token_required
+def test_jwt(current_user):
+ """测试JWT令牌接口(需要登录)"""
+ try:
+ # 获取当前请求的token(从装饰器已验证的Authorization header)
+ auth_header = request.headers.get('Authorization')
+ current_token = auth_header[7:] if auth_header and auth_header.startswith('Bearer ') else None
+
+ print(f"当前用户: {current_user.username}")
+ print(f"当前用户ID: {current_user.id}")
+ print(current_user.role)
+ print(f"Token验证成功: {current_token[:20]}..." if current_token else "No token")
+
+ # 可选:检查请求体中是否有额外的token需要验证
+ data = request.get_json() or {}
+ additional_token = data.get('token')
+
+ response_data = {
+ 'success': True,
+ 'message': 'JWT令牌验证成功',
+ 'user': current_user.to_dict(),
+ 'token_info': {
+ 'header_token_verified': True,
+ 'token_preview': current_token[:20] + "..." if current_token else None
+ }
+ }
+
+ # 如果请求体中有额外的token,也验证一下
+ if additional_token:
+ try:
+ additional_result = FAuth.verify_token(additional_token)
+ response_data['additional_token_verification'] = additional_result
+ print(f"额外token验证结果: {additional_result}")
+ except Exception as e:
+ response_data['additional_token_verification'] = {
+ 'success': False,
+ 'message': f'额外token验证失败: {str(e)}'
+ }
+
+ return jsonify(response_data), 200
+
+ except Exception as e:
+ print(f"test_jwt 错误: {str(e)}")
+ return jsonify({
+ 'success': False,
+ 'message': f'JWT令牌验证失败: {str(e)}'
+ }), 500
\ No newline at end of file