Enhance user role management and access control in the application. Added user management link in the navigation for admins. Updated login flow to redirect to Casdoor for authentication. Improved logging for user actions and unauthorized access attempts. Adjusted role checks across various views to include '管理员' and 'admin' for access permissions.
This commit is contained in:
Binary file not shown.
@@ -11,6 +11,7 @@ from views.manual import init_manual_routes
|
||||
from views.device import init_device_routes
|
||||
from views.about import init_about_routes
|
||||
from views.dashboard import init_dashboard_routes
|
||||
from views.user import init_user_routes
|
||||
import logging
|
||||
from logging.handlers import RotatingFileHandler
|
||||
import os
|
||||
@@ -80,6 +81,7 @@ def create_app():
|
||||
init_device_routes(app)
|
||||
init_about_routes(app)
|
||||
init_dashboard_routes(app)
|
||||
init_user_routes(app)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
@@ -7,3 +7,63 @@
|
||||
2025-12-10 15:06:50 INFO: 用户 韦矍森 访问历史记录页面
|
||||
2025-12-10 15:06:51 INFO: 用户 韦矍森 访问统计页面
|
||||
2025-12-10 15:06:54 INFO: 用户 韦矍森 访问仪表盘页面
|
||||
2025-12-10 15:09:46 INFO: 应用启动
|
||||
2025-12-10 15:09:46 INFO: 错误处理器初始化完成
|
||||
2025-12-10 15:11:12 INFO: 应用启动
|
||||
2025-12-10 15:11:12 INFO: 错误处理器初始化完成
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:12 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:16 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:11:16 WARNING: 未授权访问:用户 New User - usp76h 尝试访问仪表盘页面
|
||||
2025-12-10 15:14:09 INFO: 用户 韦矍森 访问仪表盘页面
|
||||
2025-12-10 15:15:06 INFO: 用户 韦矍森 开始同步离线设备
|
||||
2025-12-10 15:15:06 INFO: 同步完成:创建了 8 个工单,恢复了 7 个设备
|
||||
2025-12-10 15:15:19 INFO: 用户 韦矍森 访问统计页面
|
||||
2025-12-10 15:15:20 INFO: 用户 韦矍森 访问历史记录页面
|
||||
2025-12-10 15:15:21 INFO: 用户 韦矍森 访问仪表盘页面
|
||||
2025-12-10 15:15:42 INFO: 用户 韦矍森(19977899008) 登出
|
||||
2025-12-10 15:16:07 INFO: 重定向到 Casdoor 授权页面
|
||||
2025-12-10 15:16:22 INFO: Casdoor 用户信息: {'sub': '798f4436-fbb6-45f4-bf0c-6e1cf4add605', 'iss': 'http://10.10.10.14:18000', 'aud': '8f323670e073612794ef', 'preferred_username': 'test', 'name': '韦矍森', 'email': 'voole@vip.qq.com', 'email_verified': True, 'picture': 'https://cdn.casbin.org/img/casbin.svg', 'phone': '19977899008'}
|
||||
2025-12-10 15:16:22 INFO: 更新用户信息: 韦矍森(19977899008)
|
||||
2025-12-10 15:16:22 INFO: 用户 韦矍森(19977899008) 通过 Casdoor 登录成功
|
||||
2025-12-10 15:16:23 INFO: 用户 韦矍森 访问仪表盘页面
|
||||
2025-12-10 15:16:43 INFO: 用户 韦矍森 访问历史记录页面
|
||||
2025-12-10 15:16:44 INFO: 用户 韦矍森 访问统计页面
|
||||
2025-12-10 15:17:08 INFO: 用户 韦矍森 访问历史记录页面
|
||||
2025-12-10 15:17:12 INFO: 用户 韦矍森 访问仪表盘页面
|
||||
2025-12-10 15:17:15 INFO: 用户 韦矍森 访问统计页面
|
||||
2025-12-10 15:17:16 INFO: 用户 韦矍森 访问历史记录页面
|
||||
2025-12-10 15:25:09 INFO: 应用启动
|
||||
2025-12-10 15:25:09 INFO: 错误处理器初始化完成
|
||||
2025-12-10 15:26:06 INFO: 应用启动
|
||||
2025-12-10 15:26:06 INFO: 错误处理器初始化完成
|
||||
2025-12-10 15:27:03 INFO: 应用启动
|
||||
2025-12-10 15:27:03 INFO: 错误处理器初始化完成
|
||||
2025-12-10 15:27:15 INFO: 应用启动
|
||||
2025-12-10 15:27:15 INFO: 错误处理器初始化完成
|
||||
2025-12-10 15:27:34 INFO: 应用启动
|
||||
2025-12-10 15:27:34 INFO: 错误处理器初始化完成
|
||||
2025-12-10 15:27:53 INFO: 应用启动
|
||||
2025-12-10 15:27:53 INFO: 错误处理器初始化完成
|
||||
2025-12-10 15:28:44 INFO: 用户 韦矍森 访问仪表盘页面
|
||||
2025-12-10 15:28:54 INFO: 应用启动
|
||||
2025-12-10 15:28:54 INFO: 错误处理器初始化完成
|
||||
2025-12-10 15:28:54 INFO: 用户信息已更新: 农远灵(19978825450) -> branch=红水河支局, role=装维员
|
||||
2025-12-10 15:29:14 INFO: 用户信息已更新: 农远灵(19978825450) -> branch=电厂支局, role=装维员
|
||||
2025-12-10 15:30:20 INFO: 用户信息已更新: 韦矍森(19977899008) -> branch=交付中心, role=管理员
|
||||
2025-12-10 15:30:22 INFO: 用户 韦矍森(19977899008) 登出
|
||||
2025-12-10 15:30:32 INFO: 重定向到 Casdoor 授权页面
|
||||
2025-12-10 15:30:32 INFO: Casdoor 用户信息: {'sub': '92501c0e-db14-4def-8ded-cb8337d8acdb', 'iss': 'http://10.10.10.14:18000', 'aud': '8f323670e073612794ef', 'preferred_username': 'admin', 'name': 'Admin', 'email': 'voole@vip.qq.com', 'email_verified': True, 'picture': 'https://cdn.casbin.org/img/casbin.svg', 'phone': '18878797071'}
|
||||
2025-12-10 15:30:32 INFO: 创建新用户: Admin(18878797071)
|
||||
2025-12-10 15:30:32 INFO: 用户 Admin(18878797071) 通过 Casdoor 登录成功
|
||||
2025-12-10 15:30:32 INFO: 用户 Admin 访问仪表盘页面
|
||||
2025-12-10 15:32:06 INFO: 应用启动
|
||||
2025-12-10 15:32:06 INFO: 错误处理器初始化完成
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0 nav_menu">
|
||||
{% if current_user.is_authenticated %}
|
||||
{% if current_user.role == '统计员' %}
|
||||
{% if current_user.role in ['统计员', '管理员', 'admin'] or current_user.name == 'Admin' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav_link {{ 'active' if request.endpoint == 'dashboard' }}" href="{{ url_for('dashboard') }}">仪表盘</a>
|
||||
</li>
|
||||
@@ -57,6 +57,9 @@
|
||||
<li class="nav-item">
|
||||
<a class="nav_link {{ 'active' if request.endpoint == 'about' }}" href="{{ url_for('about') }}">关于</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav_link {{ 'active' if request.endpoint == 'user_list' }}" href="{{ url_for('user_list') }}">用户管理</a>
|
||||
</li>
|
||||
{% elif current_user.role == '装维员' %}
|
||||
<li class="nav-item">
|
||||
<a class="nav_link {{ 'active' if request.endpoint == 'dashboard' }}" href="{{ url_for('dashboard') }}">仪表盘</a>
|
||||
|
||||
+18
-33
@@ -5,40 +5,25 @@
|
||||
<h2 class="login_title">欢迎使用</h2>
|
||||
<div class="login_subtitle">大化重点项目工单管理平台</div>
|
||||
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="login_error">
|
||||
{% for message in messages %}
|
||||
{{ message }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% if casdoor_enabled %}
|
||||
<!-- Casdoor 登录按钮 -->
|
||||
<div class="login_casdoor_section">
|
||||
<a href="{{ url_for('casdoor_login') }}" class="login_button login_button_casdoor">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-right: 8px;">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" fill="currentColor"/>
|
||||
</svg>
|
||||
使用 Casdoor 登录
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="login_divider">
|
||||
<span>或</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<!-- 原有手机号登录表单 -->
|
||||
<form method="POST" class="login_form">
|
||||
<div class="login_input_group">
|
||||
<label for="phone" class="login_label">用户名(手机号)</label>
|
||||
<input type="text" id="phone" name="phone" class="login_input" placeholder="请输入手机号" required>
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="login_error">
|
||||
{% for message in messages %}
|
||||
{{ message }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<button type="submit" class="login_button login_button_phone">手机号登录</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<!-- Casdoor 登录按钮 -->
|
||||
<div class="login_casdoor_section">
|
||||
<a href="{{ url_for('casdoor_login') }}" class="login_button login_button_casdoor">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="margin-right: 8px;">
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z" fill="currentColor"/>
|
||||
</svg>
|
||||
使用 Casdoor 登录
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<div class="container mt-4">
|
||||
<h2 class="mb-3">用户管理</h2>
|
||||
|
||||
{% with messages = get_flashed_messages() %}
|
||||
{% if messages %}
|
||||
<div class="alert alert-info">
|
||||
{% for message in messages %}
|
||||
{{ message }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>手机号</th>
|
||||
<th>姓名</th>
|
||||
<th>所属支局</th>
|
||||
<th>角色</th>
|
||||
<th style="width: 160px;">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for user in users %}
|
||||
<tr>
|
||||
<form method="POST" action="{{ url_for('update_user', phone=user.phone) }}">
|
||||
<td>{{ user.phone }}</td>
|
||||
<td>{{ user.name }}</td>
|
||||
<td>
|
||||
<select name="branch" class="form-select">
|
||||
<option value="" {% if not user.branch %}selected{% endif %}>未设置</option>
|
||||
{% for branch in branch_options %}
|
||||
<option value="{{ branch }}" {% if user.branch == branch %}selected{% endif %}>{{ branch }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<select name="role" class="form-select" required>
|
||||
{% for role in role_options %}
|
||||
<option value="{{ role }}" {% if user.role == role %}selected{% endif %}>{{ role }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<button type="submit" class="btn btn-primary btn-sm">保存</button>
|
||||
</td>
|
||||
</form>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
-18
@@ -9,26 +9,10 @@ def init_auth_routes(app):
|
||||
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
# 如果已登录,直接跳转到仪表盘
|
||||
# 已登录直接进入仪表盘,否则跳转 Casdoor 登录
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
# 检查是否启用了 Casdoor
|
||||
casdoor_enabled = bool(app.config.get('CASDOOR_CLIENT_ID'))
|
||||
|
||||
# 处理手机号登录
|
||||
if request.method == 'POST':
|
||||
phone = request.form['phone']
|
||||
user = User.query.filter_by(phone=phone).first()
|
||||
if user:
|
||||
login_user(user)
|
||||
app.logger.info(f'用户 {user.name}({user.phone}) 登录成功')
|
||||
return redirect(url_for('dashboard'))
|
||||
else:
|
||||
app.logger.warning(f'登录失败:用户不存在 (手机号: {phone})')
|
||||
flash('用户不存在')
|
||||
|
||||
return render_template('login.html', casdoor_enabled=casdoor_enabled)
|
||||
return redirect(url_for('casdoor_login'))
|
||||
|
||||
@app.route('/casdoor/login')
|
||||
def casdoor_login():
|
||||
|
||||
@@ -9,7 +9,8 @@ def init_dashboard_routes(app):
|
||||
@app.route('/dashboard')
|
||||
@login_required
|
||||
def dashboard():
|
||||
if current_user.role not in ['装维员', '统计员']:
|
||||
allowed_roles = ['装维员', '统计员', '管理员', 'admin']
|
||||
if current_user.role not in allowed_roles and current_user.name != 'Admin':
|
||||
app.logger.warning(f'未授权访问:用户 {current_user.name} 尝试访问仪表盘页面')
|
||||
flash('您没有权限访问此页面')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
+2
-1
@@ -14,7 +14,8 @@ def init_device_routes(app):
|
||||
@app.route('/sync_offline_devices', methods=['POST'])
|
||||
@login_required
|
||||
def sync_offline_devices():
|
||||
if current_user.role not in ['装维员', '统计员']:
|
||||
allowed_roles = ['装维员', '统计员', '管理员', 'admin']
|
||||
if current_user.role not in allowed_roles and current_user.name != 'Admin':
|
||||
app.logger.warning(f'未授权访问:用户 {current_user.name} 尝试同步离线设备')
|
||||
return jsonify({'success': False, 'message': '没有权限执行此操作'})
|
||||
|
||||
|
||||
@@ -7,7 +7,8 @@ def init_history_routes(app):
|
||||
@app.route('/history')
|
||||
@login_required
|
||||
def history():
|
||||
if current_user.role not in ['装维员', '统计员']:
|
||||
allowed_roles = ['装维员', '统计员', '管理员', 'admin']
|
||||
if current_user.role not in allowed_roles and current_user.name != 'Admin':
|
||||
app.logger.warning(f'未授权访问:用户 {current_user.name} 尝试访问历史记录')
|
||||
flash('您没有权限访问此页面')
|
||||
return redirect(url_for('statistics'))
|
||||
@@ -110,7 +111,8 @@ def init_history_routes(app):
|
||||
@app.route('/history/<string:order_id>')
|
||||
@login_required
|
||||
def history_detail(order_id):
|
||||
if current_user.role not in ['装维员', '统计员']:
|
||||
allowed_roles = ['装维员', '统计员', '管理员', 'admin']
|
||||
if current_user.role not in allowed_roles and current_user.name != 'Admin':
|
||||
app.logger.warning(f'未授权访问:用户 {current_user.name} 尝试查看工单详情 {order_id}')
|
||||
flash('您没有权限访问此页面')
|
||||
return redirect(url_for('statistics'))
|
||||
|
||||
+2
-1
@@ -11,7 +11,8 @@ def init_manual_routes(app):
|
||||
@app.route('/manual', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def manual():
|
||||
if current_user.role not in ['装维员', '统计员']:
|
||||
allowed_roles = ['装维员', '统计员', '管理员', 'admin']
|
||||
if current_user.role not in allowed_roles and current_user.name != 'Admin':
|
||||
app.logger.warning(f'未授权访问:用户 {current_user.name} 尝试访问手工故障单页面')
|
||||
flash('您没有权限访问此页面')
|
||||
return redirect(url_for('statistics'))
|
||||
|
||||
@@ -13,7 +13,8 @@ def init_statistics_routes(app):
|
||||
@app.route('/statistics')
|
||||
@login_required
|
||||
def statistics():
|
||||
if current_user.role not in ['装维员', '统计员']:
|
||||
allowed_roles = ['装维员', '统计员', '管理员', 'admin']
|
||||
if current_user.role not in allowed_roles and current_user.name != 'Admin':
|
||||
app.logger.warning(f'未授权访问:用户 {current_user.name} 尝试访问统计页面')
|
||||
flash('您没有权限访问此页面')
|
||||
return redirect(url_for('login'))
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
from flask import render_template, request, redirect, url_for, flash
|
||||
from flask_login import login_required, current_user
|
||||
from scripts.models import db, User, Device
|
||||
|
||||
|
||||
def init_user_routes(app):
|
||||
def is_admin_user():
|
||||
"""允许统计员/管理员或名称为 Admin 的用户管理账号"""
|
||||
return current_user.role in ['统计员', '管理员', 'admin'] or current_user.name == 'Admin'
|
||||
|
||||
@app.route('/users', methods=['GET'])
|
||||
@login_required
|
||||
def user_list():
|
||||
if not is_admin_user():
|
||||
app.logger.warning(f'未授权访问:用户 {current_user.name} 尝试访问用户管理')
|
||||
flash('您没有权限访问此页面')
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
users = User.query.order_by(User.name).all()
|
||||
branch_options = [b[0] for b in db.session.query(Device.branch).distinct().all() if b[0]]
|
||||
role_options = ['统计员', '装维员', '管理员']
|
||||
|
||||
return render_template(
|
||||
'users.html',
|
||||
users=users,
|
||||
branch_options=branch_options,
|
||||
role_options=role_options
|
||||
)
|
||||
|
||||
@app.route('/users/<phone>', methods=['POST'])
|
||||
@login_required
|
||||
def update_user(phone):
|
||||
if not is_admin_user():
|
||||
app.logger.warning(f'未授权访问:用户 {current_user.name} 尝试修改用户 {phone}')
|
||||
flash('您没有权限执行此操作')
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
user = User.query.filter_by(phone=phone).first()
|
||||
if not user:
|
||||
flash('用户不存在')
|
||||
return redirect(url_for('user_list'))
|
||||
|
||||
new_branch = request.form.get('branch', '').strip()
|
||||
new_role = request.form.get('role', '').strip()
|
||||
|
||||
if new_role and new_role not in ['统计员', '装维员', '管理员']:
|
||||
flash('角色不合法')
|
||||
return redirect(url_for('user_list'))
|
||||
|
||||
user.branch = new_branch
|
||||
user.role = new_role
|
||||
db.session.commit()
|
||||
app.logger.info(f'用户信息已更新: {user.name}({user.phone}) -> branch={user.branch}, role={user.role}')
|
||||
flash('用户信息已更新')
|
||||
return redirect(url_for('user_list'))
|
||||
|
||||
@@ -17,7 +17,8 @@ def init_work_order_routes(app):
|
||||
@app.route('/dispatch', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def dispatch():
|
||||
if current_user.role not in ['装维员', '统计员']:
|
||||
allowed_roles = ['装维员', '统计员', '管理员', 'admin']
|
||||
if current_user.role not in allowed_roles and current_user.name != 'Admin':
|
||||
flash('您没有权限访问此页面')
|
||||
return redirect(url_for('statistics'))
|
||||
|
||||
@@ -283,7 +284,8 @@ def init_work_order_routes(app):
|
||||
@app.route('/receive/<string:work_order_id>', methods=['GET', 'POST'])
|
||||
@login_required
|
||||
def receive_detail(work_order_id):
|
||||
if current_user.role not in ['装维员', '统计员']:
|
||||
allowed_roles = ['装维员', '统计员', '管理员', 'admin']
|
||||
if current_user.role not in allowed_roles and current_user.name != 'Admin':
|
||||
flash('您没有权限访问此页面')
|
||||
return redirect(url_for('statistics'))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user