当前位置: 首页 > news >正文

手机检测WebUI权限管理:基于OAuth2的多角色(管理员/监考员)控制

手机检测WebUI权限管理:基于OAuth2的多角色(管理员/监考员)控制

1. 项目背景与需求

想象一下,你部署了一个手机检测系统,用来在考场里监控学生有没有偷偷用手机。系统跑起来了,效果也不错,但很快你发现一个问题:所有人都能访问这个系统,谁都能上传图片、查看检测结果。这显然不行。

监考老师需要用它来实时监控,但你不能让他们有权限去修改系统设置或者删除日志。系统管理员需要维护整个服务,但又不能让他们在考试期间随意操作影响监考。这就是权限管理的核心需求——不同的人,干不同的事,看到不同的界面

今天要聊的,就是怎么给这个基于DAMO-YOLO和TinyNAS的手机检测WebUI,加上一套靠谱的权限控制系统。我们选择OAuth2这个行业标准协议来实现,它能清晰地划分出“管理员”和“监考员”两种角色,让系统既安全又好用。

2. 为什么选择OAuth2?

你可能听过OAuth2,它常被用在“用微信登录”、“用GitHub账号登录”这种场景。其实,它同样非常适合我们这种内部系统的权限管理。

简单来说,OAuth2解决了几个关键问题:

  1. 不用自己管密码:系统不需要存储用户的明文密码,安全性更高。
  2. 权限分得清:可以精确控制某个角色能访问哪些接口(API),能进行哪些操作。
  3. 令牌化访问:用户登录后拿到一个“令牌”(Token),后续操作都靠这个令牌来识别身份和权限,过期了可以刷新。
  4. 标准协议:方案成熟,有大量现成的库和工具支持,自己从头写的坑太多了。

对于我们的手机检测系统,OAuth2能让我们轻松实现:

  • 监考员:只能访问检测页面,上传图片,查看本次检测结果。
  • 管理员:可以访问所有页面,包括用户管理、日志查看、服务配置等。

3. 系统架构与核心概念

在动手之前,我们先理清两个核心概念和整个系统的架构。

3.1 角色定义(Role Definition)

我们定义两种角色,权限由高到低:

  • 管理员 (Admin)

    • 权限:拥有系统的全部操作权限。
    • 可访问功能:手机检测、用户管理(增删改查监考员)、查看所有操作日志、系统服务管理(重启、停止)、模型配置管理。
    • 典型用户:IT运维人员、系统负责人。
  • 监考员 (Proctor)

    • 权限:仅拥有执行检测任务的相关权限。
    • 可访问功能:手机检测页面(上传图片、查看检测结果)、查看本人的操作历史。
    • 典型用户:监考老师、考场工作人员。

3.2 权限范围(Scope)

Scope是OAuth2中用于细分权限的标识符。我们可以为不同功能定义不同的Scope,然后给角色分配对应的Scope集合。

  • detect:run:执行手机检测任务。
  • detect:history:查看检测历史记录。
  • user:read:读取用户信息。
  • user:write:创建、修改用户信息。
  • log:read:查看系统日志。
  • system:manage:管理系统服务(如重启应用)。

角色-Scope分配关系

  • 监考员[detect:run, detect:history]
  • 管理员[detect:run, detect:history, user:read, user:write, log:read, system:manage]

3.3 整体架构图

加了权限管理后,系统不再是简单的一个WebUI,而是变成了这样:

┌─────────────────┐ ┌──────────────────────────────────┐ │ │ │ │ │ 用户浏览器 │────▶│ 手机检测WebUI (Gradio) │ │ │ │ │ └─────────────────┘ └───────────────┬──────────────────┘ │ │ 携带Access Token访问 ▼ ┌─────────────────────────────────────────────────────────┐ │ OAuth2 授权服务器 │ │ ├── 用户认证 (登录) │ │ ├── 角色与权限校验 │ │ └── 颁发访问令牌 (Access Token) │ └─────────────────────────────────────────────────────────┘ │ │ 校验Token与权限 ▼ ┌─────────────────┐ ┌──────────────────────────────────┐ │ │ │ │ │ DAMO-YOLO │◀───│ 业务逻辑与模型API │ │ 检测模型 │ │ (根据权限决定是否处理请求) │ │ │ │ │ └─────────────────┘ └──────────────────────────────────┘

工作流程

  1. 用户打开WebUI,被重定向到登录页面。
  2. 用户输入账号密码,OAuth2服务器验证身份并确认其角色(管理员/监考员)。
  3. 服务器根据角色生成包含对应scopeaccess_token,返回给WebUI。
  4. 此后,用户每次向WebUI发起请求(如上传图片),WebUI都会在后台携带这个token去问授权服务器:“这个人能执行这个操作吗?”
  5. 授权服务器校验token有效性和scope,返回“允许”或“拒绝”。
  6. WebUI根据结果,决定是正常响应请求,还是返回一个“权限不足”的错误。

4. 代码实现详解

理论说完了,我们来看看具体怎么在现有的Gradio WebUI里加入这套东西。我们会用到authlib这个Python OAuth2库,它能让实现过程简单不少。

4.1 环境准备与依赖安装

首先,在原来的requirements.txt文件里添加新的依赖:

# 原有依赖 modelscope gradio>=4.0.0 torch opencv-python pillow supervisor # 新增权限管理依赖 authlib==1.3.0 # OAuth2服务器库 itsdangerous==2.2.0 # 用于生成和解析令牌 python-jose[cryptography]==3.3.0 # JWT令牌操作 passlib[bcrypt]==1.7.4 # 密码哈希加密

然后安装它们:

pip install -r requirements.txt

4.2 构建用户数据库

我们用一个简单的Python字典在内存里模拟用户数据库。在实际生产环境,你应该换成SQLite、MySQL或PostgreSQL。

创建一个新文件auth_server.py

# auth_server.py - OAuth2授权服务器核心 from datetime import datetime, timedelta from typing import Optional, Dict import json from jose import JWTError, jwt from passlib.context import CryptContext # 模拟用户数据库 # 格式:username: {‘hashed_password‘, ‘role‘, ‘scopes‘} fake_users_db = { "admin": { "username": "admin", "full_name": "系统管理员", "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", # 密码明文是"secret" "role": "admin", "scopes": ["detect:run", "detect:history", "user:read", "user:write", "log:read", "system:manage"], "disabled": False, }, "proctor_zhang": { "username": "proctor_zhang", "full_name": "张监考员", "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", # 密码明文也是"secret" "role": "proctor", "scopes": ["detect:run", "detect:history"], "disabled": False, }, } # 密码加密上下文 pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # JWT令牌配置 SECRET_KEY = "your-secret-key-please-change-this-in-production" # 生产环境务必更换! ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 def verify_password(plain_password, hashed_password): """验证密码""" return pwd_context.verify(plain_password, hashed_password) def get_user(username: str): """从数据库获取用户""" if username in fake_users_db: user_dict = fake_users_db[username] return user_dict return None def authenticate_user(username: str, password: str): """用户认证""" user = get_user(username) if not user: return False if not verify_password(password, user["hashed_password"]): return False return user def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): """创建JWT访问令牌""" to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta else: expire = datetime.utcnow() + timedelta(minutes=15) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt

4.3 集成OAuth2到Gradio WebUI

接下来,修改主应用文件(比如app.py),将登录和权限检查集成进去。

# app.py - 主应用文件(部分修改) import gradio as gr from auth_server import authenticate_user, create_access_token, SECRET_KEY, ALGORITHM from jose import JWTError, jwt from datetime import timedelta import json # 存储当前登录用户令牌的全局变量(简单示例,生产环境应用更安全的方式) current_user_token = None current_user_info = None def login(username: str, password: str): """登录函数,供Gradio界面调用""" global current_user_token, current_user_info user = authenticate_user(username, password) if not user: return "登录失败:用户名或密码错误", gr.update(visible=False) # 创建访问令牌 access_token_expires = timedelta(minutes=30) access_token = create_access_token( data={"sub": user["username"], "scopes": user["scopes"]}, expires_delta=access_token_expires, ) current_user_token = access_token current_user_info = user # 根据角色返回不同的欢迎信息和界面控制 welcome_msg = f"欢迎回来,{user['full_name']} ({user['role']})!" if user["role"] == "admin": return welcome_msg, gr.update(visible=True) # 管理员显示所有标签页 else: return welcome_msg, gr.update(visible=False) # 监考员隐藏管理标签页 def verify_token_and_scope(required_scope: str): """验证令牌和权限的装饰器(核心)""" def decorator(func): def wrapper(*args, **kwargs): global current_user_token, current_user_info if not current_user_token: return "错误:请先登录系统", None try: # 解码并验证JWT令牌 payload = jwt.decode(current_user_token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") token_scopes = payload.get("scopes", []) if username is None: return "错误:无效的令牌", None # 检查权限范围 if required_scope not in token_scopes: return f"错误:权限不足。需要‘{required_scope}‘权限。", None # 权限验证通过,执行原函数 return func(*args, **kwargs) except JWTError: return "错误:令牌无效或已过期,请重新登录", None return wrapper return decorator # --- 原有检测函数,现在加上权限检查 --- @verify_token_and_scope("detect:run") def detect_phone(image): """执行手机检测(需要detect:run权限)""" # 这里是原有的DAMO-YOLO检测逻辑 # ... (你的检测代码) ... num_phones = 2 # 假设结果 confidence = 0.95 return processed_image, f"检测到 {num_phones} 部手机,平均置信度 {confidence:.1%}" # --- 构建Gradio界面,根据权限动态显示 --- with gr.Blocks(title="手机检测系统 - 权限管理版") as demo: gr.Markdown("# 📱 实时手机检测系统 - 多角色权限管理") # 登录界面 with gr.Row(): with gr.Column(scale=1): gr.Markdown("### 系统登录") login_username = gr.Textbox(label="用户名", placeholder="输入用户名") login_password = gr.Textbox(label="密码", placeholder="输入密码", type="password") login_button = gr.Button("登录") login_status = gr.Textbox(label="登录状态", interactive=False) with gr.Column(scale=2): # 登录后才显示的主功能区域 main_tabs = gr.Tabs(visible=False) # 初始隐藏 with main_tabs: # 标签页1:手机检测(监考员和管理员都能看) with gr.TabItem("手机检测", id="detect"): gr.Markdown("### 上传图片进行手机检测") input_image = gr.Image(label="上传图片", type="filepath") detect_button = gr.Button("开始检测", variant="primary") output_image = gr.Image(label="检测结果") result_text = gr.Textbox(label="检测信息") detect_button.click( fn=detect_phone, inputs=input_image, outputs=[output_image, result_text] ) # 标签页2:检测历史(监考员和管理员都能看,但数据范围不同) with gr.TabItem("检测历史", id="history"): gr.Markdown("### 历史检测记录") # ... 历史记录展示逻辑 ... # 标签页3:用户管理(仅管理员可见) with gr.TabItem("用户管理", id="user_manage", visible=False): gr.Markdown("### 用户管理面板") # 这个标签页的可见性会在登录后根据角色动态设置 # ... 用户管理逻辑 ... # 标签页4:系统日志(仅管理员可见) with gr.TabItem("系统日志", id="system_log", visible=False): gr.Markdown("### 系统运行日志") # ... 日志查看逻辑 ... # 登录按钮事件 login_button.click( fn=login, inputs=[login_username, login_password], outputs=[login_status, main_tabs] ) # 启动应用 if __name__ == "__main__": demo.launch(server_name="0.0.0.0", server_port=7860, share=False)

4.4 前后端交互与令牌传递

在上面的简单示例中,我们把令牌存在了Python全局变量里,这仅适用于单用户、单会话的演示。真实场景中,Web前端(浏览器)和后端需要安全地传递令牌。

更安全的做法是:

  1. 前端登录:用户在前端登录,后端验证后返回access_token
  2. 前端存储:前端将token安全存储(例如HttpOnly的Cookie,或localStorage但需防范XSS)。
  3. 请求携带:前端每次调用Gradio后端接口时,在HTTP请求头中携带令牌:
    Authorization: Bearer <your_access_token>
  4. 后端校验:Gradio后端(或一个独立的API网关/中间件)拦截请求,从Authorization头中取出token,调用我们写的verify_token_and_scope函数进行校验。

这样,权限校验的逻辑就和业务逻辑(手机检测)解耦了,更加清晰和安全。

5. 部署与配置指南

代码写好了,我们来看看怎么把它和原来的手机检测系统一起部署起来。

5.1 项目结构更新

部署前,你的项目目录应该看起来像这样:

/root/phone-detection/ ├── app.py # 主Gradio应用(已集成权限) ├── auth_server.py # OAuth2认证服务器逻辑 ├── requirements.txt # 依赖列表(已更新) ├── start.sh # 启动脚本 ├── stop.sh # 停止脚本 ├── models/ # DAMO-YOLO模型文件 │ └── damo_yolo_s.pth ├── logs/ # 日志目录 │ ├── access.log │ └── error.log └── config/ # 新增配置目录 ├── users.yaml # 用户配置文件(替代fake_db) └── oauth_config.yaml # OAuth2服务器配置

5.2 启动脚本修改

更新start.sh脚本,确保服务启动时加载所有模块:

#!/bin/bash # start.sh - 启动手机检测WebUI服务(带权限管理) echo "启动手机检测WebUI服务(带权限管理)..." echo "当前目录: $(pwd)" # 激活Python虚拟环境(如果你有的话) # source /path/to/venv/bin/activate # 安装依赖(首次运行或依赖有更新时) echo "检查并安装Python依赖..." pip install -r requirements.txt -q # 启动Gradio应用 echo "启动主应用服务器..." python app.py & # 记录进程ID(可选,用于管理) echo $! > /tmp/phone_detection_ui.pid echo "服务启动完成!" echo "访问地址: http://$(hostname -I | awk '{print $1}'):7860" echo "使用Ctrl+C停止服务"

5.3 Supervisor配置更新

如果你用Supervisor管理服务,需要更新配置文件,确保环境变量和路径正确。

; /etc/supervisor/conf.d/phone-detection-oauth.conf [program:phone-detection-oauth] command=/usr/bin/python3 /root/phone-detection/app.py directory=/root/phone-detection user=root autostart=true autorestart=true stopasgroup=true killasgroup=true stderr_logfile=/root/phone-detection/logs/error.log stdout_logfile=/root/phone-detection/logs/access.log environment=SECRET_KEY="your-production-secret-key-change-me",PYTHONPATH="/root/phone-detection"

更新配置后,重启Supervisor并启动新服务:

# 重新加载Supervisor配置 sudo supervisorctl reread sudo supervisorctl update # 启动新服务 sudo supervisorctl start phone-detection-oauth # 查看状态 sudo supervisorctl status phone-detection-oauth

6. 使用体验与效果

部署完成后,我们来看看不同角色的用户会看到什么。

6.1 监考员视角

  1. 登录:监考员proctor_zhang使用自己的账号登录。
  2. 界面:登录后,他只能看到两个标签页:“手机检测”和“检测历史”。
  3. 操作
    • 在“手机检测”页面上传考场图片,系统自动标记出手机。
    • 在“检测历史”页面,只能查看自己账号下的检测记录。
  4. 限制:他完全看不到“用户管理”和“系统日志”标签页。如果他试图通过直接输入URL访问管理页面,后端权限校验会拦截并返回“权限不足”错误。

6.2 管理员视角

  1. 登录:管理员admin登录。
  2. 界面:登录后,他看到完整的四个标签页:“手机检测”、“检测历史”、“用户管理”、“系统日志”。
  3. 操作
    • 拥有监考员的所有功能。
    • 可以在“用户管理”中新增、禁用监考员账号。
    • 可以在“系统日志”中查看所有用户的操作记录和系统运行状态。
    • 可以重启后端检测服务(如果实现了该功能)。

6.3 实际效果对比

功能模块监考员 (Proctor)管理员 (Admin)
手机检测✅ 完全可用✅ 完全可用
查看检测历史✅ 仅看本人记录✅ 查看所有记录
用户管理❌ 不可见/无权限✅ 增删改查用户
查看系统日志❌ 不可见/无权限✅ 查看完整日志
服务管理❌ 无权限✅ 重启、停止服务

7. 总结

给手机检测WebUI加上基于OAuth2的权限管理,听起来复杂,但拆解开来就是“(用户)能用什么(Scope)功能”的问题。我们通过今天的设计和实现,达到了几个关键目标:

  1. 职责分离:监考员专注监考任务,管理员负责系统维护,权责清晰。
  2. 安全提升:避免了未授权访问和越权操作的风险。令牌机制也避免了密码在网络上频繁传输。
  3. 可扩展性强:OAuth2的scope设计非常灵活。如果未来需要增加“巡考员”角色(只能看记录,不能检测),或者增加新的功能模块(如“报表导出”),只需要定义新的scope并分配给对应角色即可,核心架构不用大改。
  4. 用户体验良好:用户登录后,界面会根据其权限动态呈现,无需看到用不到的功能,简洁高效。

下一步可以优化的方向

  • 持久化存储:将用户数据库从内存字典迁移到SQLite或MySQL。
  • 更精细的权限:在scope基础上,实现数据行级的权限控制(例如,监考员只能查看自己考场的记录)。
  • 独立的授权服务器:将auth_server.py拆分成一个独立的微服务,供多个系统共用。
  • 前端路由守卫:在前端(如果使用更复杂的前端框架)也加入权限检查,隐藏无权限的菜单或按钮,提供更好的交互反馈。

希望这篇从零到一的指南,能帮你为你的手机检测系统,乃至其他需要权限控制的内部工具,构建一个清晰、安全、专业的访问控制层。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

http://www.cnnetsun.cn/news/1294659.html

相关文章:

  • 立创开源:基于中科蓝汛AB5301A与启英泰伦CI1302的离线语音蓝牙音箱全方案解析
  • DeepSeek-R1 1.5B完全指南:下载、部署、使用、优化一步到位
  • Cesium模型与视频结合实战:提升三维场景动态展示效率的解决方案
  • 4大优势!FastAPI Admin让后台开发效率提升80%
  • YimMenu全面指南:从入门到精通的开源GTA V辅助工具
  • 我写了一本从零实现深度学习与大语言模型的入门教程
  • 从行程编码到形态学:Halcon中erosion、connection、fill_up的算法实现与优化
  • 【第二周】RAG与Agent实战07:提示词优化案例_金融信息抽取
  • 0314爬紫金山
  • ChatGPT Python SDK深度实战:从API封装到生产环境最佳实践
  • Android应用集成AI:将Nanbeige 4.1-3B模型API封装为移动端SDK
  • 51单片机时钟电路设计避坑指南:从晶振选型到PCB布局的5个关键细节
  • wps word 修改无格式粘贴快捷键为 ctrl+shift+v
  • 如何突破SIM卡区域限制?3大创新技术重构跨境网络体验
  • MPh颠覆式仿真自动化:全流程工程问题的Python解决方案
  • 逆向解析百度搜索核心技术
  • 基于立创泰山派RK3566开发板打造智能小手机:从硬件选型到系统编译全流程实战
  • 3步突破流体测量瓶颈:面向科研人员的PIVlab实战指南
  • AI头像生成器效果展示:写实人像Prompt生成——毛孔细节/发丝纹理/自然阴影
  • E5071C数据管理进阶:从本地SNP/CSV到云端SCPI脚本的自动化实践
  • 实时数据推送新选择:SSE技术解析
  • JavaScript性能优化实战卣藏
  • JavaScript性能优化实战致籽
  • 雷电模拟器上运行Frida 16.0.10的避坑指南:从安装到实战
  • Qwen3-0.6B-FP8快速部署教程:应对高并发对话的架构设计
  • 基于PT2023的单芯片触控调光小夜灯硬件设计
  • 避坑指南:Windows系统kubectl安装后连接k8s集群的5个常见问题解决
  • VideoAgentTrek Screen Filter 高并发架构设计:支持千人同时在线屏幕审核
  • 突破Switch游戏安装瓶颈:Awoo Installer的全场景解决方案
  • 从递归平均到最优估计:卡尔曼滤波的数学直觉与核心公式推导