校园网认证系统重写实战:Django+Vue+RBAC权限管理全解析
2026/9/24 20:43:39 网站建设 项目流程

去年接到一个挺磨人的需求:学校网络管理中心的老认证系统要重写了。旧系统是十年前用 PHP 写的,登录、计费、角色切换逻辑全堆在一个控制器里,换一个管理员密码都恨不得翻半个小时的代码,日常运维的人心态早就崩了。折腾了两个月,我和另一位同事用 Python + Vue 重写了一套校园网络认证与访问控制系统,后端主体跑在 Django 上,几个独立小服务用 Flask 扛,开发环境统一在 PyCharm 里完成。这套系统上线之后,接手维护的同事反馈最多的一句话是“原来代码还能写成这样”。

这篇文章不打算按教科书讲,我把整个项目从选型、建工程、写认证、做访问控制,到前端联调和部署踩坑的顺序捋一遍。适合正在做校园项目、毕业设计,或者第一次用 Python + Vue 写带权限管理的 Web 系统的朋友。你会发现大部分难点不在“登录怎么做”,而在“放行谁、拦截谁、怎么方便地调整策略”。

1. 校园网认证系统,难点不在“认证”而在“访问控制”

1.1 需求拆解:一个认证系统要覆盖哪些人、哪些设备、哪些场景

校园网络认证系统的核心使用场景说起来不复杂:学生和老师要连入校园网,系统判断是不是合法账号;连进去之后,不同的人能访问的资源不一样。比如学生账号只能访问教学系统和图书馆资源,教师账号可以访问教务后台,网络管理员还需要能做账号冻结、流量审计和策略下发。

把这些场景翻译成技术需求,就是三件事:身份认证解决“你是谁”,会话管理解决“你登录后我怎么记住你”,访问控制解决“你进来之后能碰什么”。很多项目团队做的时候把大量精力放在登录页好不好看、验证码好不好用上,结果上线之后才发现权限关系是一团乱麻,改起来比重新做还麻烦。

在设计这套系统时,我先把角色权限关系梳理成了一张矩阵表格:角色、可访问模块、可执行操作、可管理数据范围。这张表是整个系统后面所有逻辑的依据,后面做后端中间件、前端路由守卫、菜单显隐,全都直接对着它来。

1.2 旧系统为什么必须重写

旧系统最大的问题不是功能少,而是没有分层。登录逻辑、数据库操作、页面渲染全部掺在一起,管理员想给某个临时访客开通一天的上网权限,得直接改数据库表。而且认证方式还停留在简单的用户名密码明文传输,没有统一会话失效机制,离职员工的账号经常处于“永远有效”的状态。

重写之后,系统按前后端分离架构重新设计。前端用 Vue 做单页应用,负责登录页、管理后台、个人自助服务台的交互;后端用 Django 做主要业务接口和权限控制;独立的小工具服务用 Flask 写,比如自助修改密码的服务、定时同步人事系统数据的脚本服务。所有开发在 PyCharm 里完成,环境统一后团队协作的沟通成本明显降低了。

1.3 为什么选 Python + Vue 这个组合

选择 Python 不只是因为熟练,更重要的是整个校园网运维团队日常处理大量脚本任务,比如解析交换机日志、统计在线用户数、对接防病毒系统,这些都是 Python 的强项。认证系统只是整个网络运维体系里的一环,用 Python 写后端能方便后续把其他运维功能吸收进来,避免“系统之间互相看不懂”的尴尬。

Vue 这边则是因为生态成熟、上手快,而且社区里现成的后台管理系统模板很多,能直接把精力集中在认证和权限逻辑上,不用从零抠 UI 组件。这套组合对于校园项目的团队构成来说非常合适:后端人员可以完全不管前端细节,前端人员只要按照接口文档对接就行。

2. 双后端并存:Django 做主体、Flask 做旁路服务的选择逻辑

2.1 Django 自带 Auth 体系,这是选它当主后端的主要原因

项目标题里同时出现了 django 和 flask,很多朋友以为这是二选一的关系。实际上在我这个项目里,两者是明确分工的。

主后端我选了 Django,核心原因就是它自带一套完整的认证和权限体系。Django 内置的django.contrib.auth提供了 User 模型、Group 模型、Permission 模型,还有基于 session 的认证机制和后台 admin 管理界面。我们项目里最核心的“角色-权限-用户”关系,Django 几乎开箱即用。

另外 Django 的 ORM 在处理复杂查询时非常省心。例如要查“最近七天登录次数超过三次、且属于教师分组的所有用户”,直接用 ORM 的链式查询就能搞定,不用手写复杂的关联 SQL。对于校园网这种数据量不大、但查询条件经常变化的场景,Django ORM 的灵活性非常合适。

2.2 Flask 在项目里负责什么

Flask 在这个项目里负责的是几个 Django 不太愿意“加班”的场景。

第一个是临时性小服务。比如校园网偶尔要出一个“临时开放端口”的功能,需要快速写一个页面让管理员提交申请、写一个接口让交换机自动执行命令。这种功能用 Django 做会显得重,要建 app、配路由、写迁移文件,而以 Flask 写一个单文件脚本就能跑起来,部署也很轻。

第二个是定时任务和事件回调。我们有一个联动服务,负责对接人事系统的数据同步,人事数据库一更新,自动触发认证系统的用户信息同步。这个服务用 Flask 写成一个常驻进程,只需要暴露一个回调接口,再把数据处理逻辑写在同一个文件里,维护成本极低。

2.3 选型对比:什么时候该用 Django,什么时候该用 Flask

我这里说得直接一点,不绕弯子:

维度DjangoFlask
用户与权限模块自带认证、分组、权限,二次开发快需要自己写或者集成第三方库
ORM 与数据库迁移内置 migrations,改模型后一条命令同步需要单独配 SQLAlchemy 和迁移工具
Admin 后台开箱即用,适合快速搭管理界面需要扩展 flask-admin
自由度和体积结构固定,适合项目协作灵活度高,适合小服务
学习曲线概念多,但体系完整简单,但要自己拼装组件
本项目中的位置认证、权限、业务接口主后端自助修改密码、数据同步、回调服务

如果只是做一个轻量 API 或脚本服务,甚至只是一个工具页,用 Flask 就足够了。但一个需要长期维护、多人协作、权限关系明确的认证与访问控制系统,老老实实用 Django 当主后端,长期看能省下非常多的开发时间。

2.4 让我确定框架分工的一个关键事件

项目启动第二周,我们接到一个需求:后勤部门要暂时给一部分外来施工人员开通校园网络访问权限,并且要限制他们最多只能访问特定几个业务系统。如果用 Flask 从零设计这套权限模型,至少要多花两天时间。而 Django 本身就提供了 permission 和 group 的管理方式,我只需要创建一个“临时施工人员”组,把几个目标系统的访问权限挂到这个组下,再把施工人员账号分到这个组里就算完事。

从那一刻起,“Django 当主力、Flask 做辅助”这个分工就没有再动摇过。后面所有涉及用户、角色、权限的改动都进 Django,所有独立小工具都扔给 Flask。

3. PyCharm 里初始化 Django 工程,这几步配置决定后续联调是否顺利

3.1 虚拟环境与解释器配置,别图省事直接用全局环境

用 PyCharm 创建 Django 项目的第一步,是配置好独立的虚拟环境。很多新手习惯直接选择全局 Python 解释器,结果后面一堆依赖版本冲突。

我这里用的方式是:在 PyCharm 里新建项目时选择Virtualenv,Python 版本选 3.10 或 3.11,然后等待 PyCharm 自动装好 venv。装好之后,用 PyCharm 的终端运行:

python -m pip install django djangorestframework django-cors-headers pymysql

这样做的好处非常明显:项目换台电脑拉到本地,只需要pip freeze > requirements.txt,到新机器上pip install -r requirements.txt就能恢复整个环境。我们项目组里有人用 Windows、有人用 macOS,这套流程没有出过一次环境不一致的问题。

3.2 创建工程和应用时的目录规划

很多个人项目一开始只有一个models.py、一个views.py,全塞在里面。但这类校园项目后续一定会加功能,我建议在创建时就按功能模块拆分 app。

我的目录结构大概是这样的:

network_auth/ ├── config/ # 工程配置目录,settings、urls、wsgi ├── apps/ │ ├── accounts/ # 用户注册、登录、认证相关 │ ├── roles/ # 角色、权限、分组管理 │ ├── network/ # 网络设备对接、在线用户管理 │ └── audit/ # 登录日志、操作审计 ├── static/ ├── templates/ └── frontend/ # 前端 Vue 项目

在 PyCharm 里依次执行:

django-admin startproject config . python manage.py startapp accounts python manage.py startapp roles

创建完应用之后,记得在settings.pyINSTALLED_APPS里注册。这一步是新手最容易漏的,经常有人说“我明明建了模型,但 migrate 不生效”,十有八九是忘了注册 app。

3.3 自定义用户模型:一个必须一开始就做的决定

Django 默认的 User 模型字段只包含用户名、密码、邮箱、姓名等基础信息。但校园网认证系统需要学号、工号、所属院系、账号状态、有效期这些字段,直接用默认模型根本无法满足。

这里有个很重要的教训:自定义 User 模型必须在第一次 migrate 之前就配置好。Django 一旦执行了初始迁移,再想切换 User 模型会非常麻烦,需要删库重来。

我建议在accounts/models.py里继承AbstractUser扩展字段:

from django.contrib.auth.models import AbstractUser from django.db import models class User(AbstractUser): student_id = models.CharField(max_length=32, blank=True, null=True, unique=True) employee_id = models.CharField(max_length=32, blank=True, null=True, unique=True) department = models.CharField(max_length=64, blank=True) account_status = models.CharField(max_length=16, default="active") expiry_date = models.DateTimeField(null=True, blank=True) class Meta: db_table = "auth_user"

然后在settings.py里指定:

AUTH_USER_MODEL = "accounts.User"

这一步做完之后,后续所有关联外键都用这个自定义 User,不用回头去改。

3.4 本机调试时,CORS 和 Host 配置必须提前处理

前后端分离开发时,前端 Vue 默认跑在http://localhost:8080,后端 Django 跑在http://localhost:8000,两者端口不同,必然出现跨域问题。

解决方式是在 Django 里安装并配置django-cors-headers

INSTALLED_APPS = [ ... "corsheaders", ] MIDDLEWARE = [ "corsheaders.middleware.CorsMiddleware", ... ] CORS_ALLOWED_ORIGINS = [ "http://localhost:8080", ]

同时把settings.py里的ALLOWED_HOSTS配成:

ALLOWED_HOSTS = ["*"]

这只建议在开发阶段用,等部署到生产环境必须收紧成具体域名,避免不必要的安全风险。

4. 认证模块实战:MTV 模式下打通注册、登录、注销

4.1 理解 Django 的 MTV 模式和教科书 MVC 的差异

每次给团队里新同事讲 Django,都要解释一遍 MTV。MVC 是 Model-View-Controller,而 Django 的 MTV 是 Model-Template-View。对应关系是:Model 负责数据,Template 负责渲染,View 负责业务逻辑和路由处理。Django 里没有传统意义的 Controller,因为 URL 路由和 View 一起承担了控制器的职责。

在我们这个系统里,前端是 Vue 单页应用,后端用 Django 只提供 JSON 接口,Template 用得少,但理解 MTV 依然重要,尤其是“视图里不要写模板逻辑”“模板里不要放业务判断”这种边界感,直接决定了代码后面能不能维护。

4.2 注册接口与用户序列化

注册接口的核心工作是创建用户、设置密码、分配默认角色。Django 中创建用户一定要用create_user方法,这个方法会自动对密码进行哈希加密,绝对不能用objects.create直接塞明文密码。

我用的是 Django REST Framework 的ModelSerializer处理注册数据:

from rest_framework import serializers from .models import User class RegisterSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True, min_length=8) class Meta: model = User fields = ["username", "password", "student_id", "department"] def create(self, validated_data): user = User.objects.create_user( username=validated_data["username"], password=validated_data["password"], student_id=validated_data.get("student_id", ""), department=validated_data.get("department", ""), ) # 默认分配到“普通学生”角色组 default_group, _ = Group.objects.get_or_create(name="student") user.groups.add(default_group) return user

这里有个细节:把默认角色分配放在注册逻辑里,而不是让前端传参。否则任何人都可以把自己注册成管理员。

4.3 登录逻辑的三个关键细节

登录接口表面简单,实际上需要注意的点非常多。我这里只挑三个对项目影响最大的说。

第一个是密码验证。我用 Django 的authenticate方法,它会自动处理哈希比对:

from django.contrib.auth import authenticate, login def login_view(request): username = request.data.get("username") password = request.data.get("password") user = authenticate(request, username=username, password=password) if user is not None: login(request, user) return JsonResponse({"code": 0, "data": {"username": user.username, "role": list(user.groups.values_list("name", flat=True))}}) return JsonResponse({"code": 1, "message": "用户名或密码错误"})

第二个是登录状态保存方式。考虑到校园网系统主要面向浏览器访问,我没有使用复杂的 JWT 方案,而是直接使用 Django 的 session 机制。服务器端保存会话,客户端保存 sessionid Cookie。这样注销时直接清掉服务端 session,控制力更强,也避免了 JWT 过期时间不好控制的麻烦。

第三个是登录成功后的返回信息。一定要返回用户的角色列表和权限标识,前端要根据这些信息决定登录后跳转哪个页面、菜单显示哪些项。如果登录接口只返回一个 “success”,前端没法区分普通学生和管理员,后面全是麻烦。

4.4 日常操作中的查询与删除对象,几个容易踩的坑

标题相关热词里有“django执行查询-删除对象”,这块确实很典型。我在项目里遇见的坑主要有三个:

第一是get方法查不到对象会抛异常。代码不能假设数据一定存在,尤其是关联查询的时候。更安全的写法是:

from django.shortcuts import get_object_or_404 user = get_object_or_404(User, username=username)

第二是删除对象时要注意级联删除。比如删除一个角色组,组下的用户关系怎么办?Django 的默认行为是级联删除关联数据,但这不一定是你想要的。需要在模型的ForeignKey字段上显式设置on_delete=models.SET_NULLon_delete=models.PROTECT

第三是批量删除时尽量用objects.filter(...).delete(),避免在 Python 层循环一条一条删,性能差距在几千条数据时就很明显了。

5. 访问控制关键:RBAC 权限模型的落地细节

5.1 什么是 RBAC,以及为什么说“django rabc”是个拼写误区

热词里有个 “django rabc”,这其实是 RBAC 的常见拼写错误。RBAC 全称是 Role-Based Access Control,基于角色的访问控制,是权限管理领域最经典、也最适合校园网这种多角色场景的模型。

RBAC 的核心思想是:用户不直接关联权限,而是关联角色,角色再关联权限。这样做的好处是,如果有一百个学生需要开通访问某系统的权限,不需要给一百个账号分别配权限,只要给“学生”这个角色加一个权限,所有学生账号自动生效。

校园网场景下典型的 RBAC 角色表大概是这样的:

角色权限范围
student访问教学系统、图书馆资源、修改个人密码
teacher学生权限 + 教务系统、成绩录入
network_admin账号管理、角色管理、在线用户管理、设备配置
operator查看日志、导出报表、临时账号开通

5.2 在 Django 里如何落地 RBAC 关系

Django 自带UserGroupPermission三个模型,天然支持 RBAC 落地。Group就是角色,Permission就是权限点,User.groups建立了用户和角色的多对多关系。

实际开发中,我为每个业务动作创建对应的权限点,例如:

python manage.py shell

然后在代码中注册权限:

from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType from .models import User content_type = ContentType.objects.get_for_model(User) permission = Permission.objects.create( codename="can_freeze_account", name="可以冻结账号", content_type=content_type, )

然后把这个权限挂到network_admin角色上:

from django.contrib.auth.models import Group admin_group = Group.objects.get(name="network_admin") admin_group.permissions.add(permission)

以后判断用户是否有权限,只需要一行代码:

user.has_perm("accounts.can_freeze_account")

这套机制全部是 Django 内置能力,不用自己重复造轮子。

5.3 后端接口鉴权中间件的实现

界面上的菜单隐藏只是防君子,后端接口必须做真正的权限拦截。我用 Django 中间件实现了一个简单的权限校验逻辑。

思路是:定义一个装饰器,标注某个接口需要什么权限码;在中间件或视图里统一检查当前用户的权限。这里我推荐用装饰器,因为更直观:

from django.http import JsonResponse from functools import wraps def require_permission(codename): def decorator(func): @wraps(func) def wrapper(request, *args, **kwargs): if not request.user.is_authenticated: return JsonResponse({"code": 401, "message": "请先登录"}, status=401) if not request.user.has_perm(codename): return JsonResponse({"code": 403, "message": "没有操作权限"}, status=403) return func(request, *args, **kwargs) return wrapper return decorator

使用的时候:

@require_permission("accounts.can_freeze_account") def freeze_user(request, user_id): ...

这个方案的扩展性很好,权限点变了只需要在装饰器里对应调整,新增接口也不会影响其他接口。

5.4 前端路由和按钮级权限控制

前端 Vue 侧的权限控制主要分两层:路由守卫控制页面级跳转,自定义指令控制按钮级显隐。

路由守卫可以这样做:

router.beforeEach((to, from, next) => { const token = localStorage.getItem('token') const roles = JSON.parse(localStorage.getItem('roles') || '[]') if (to.meta.requiresAuth && !token) { next('/login') } else if (to.meta.roles && !to.meta.roles.some(r => roles.includes(r))) { next('/403') } else { next() } })

这种方法把角色信息保存在前端 localStorage,可以快速判断页面访问权限,避免每次跳转都请求后端。后面我会提到,更严格的方案是在后端再校验一次,但前端先做拦截体验更好。

6. Vue 前端接入的实操细节与常见报错

6.1 Vue 环境安装与依赖版本,安装依赖时的关心点

Vue 项目的创建建议直接用官方脚手架。在 PyCharm 自带的终端里执行:

npm create vue@latest

或者如果要用 Vue 3 + Vite 的标准模板:

npm create vite@latest frontend -- --template vue

创建之后进入目录安装依赖:

cd frontend npm install

这里需要提醒的是:新版本脚手架默认安装的依赖版本很新,有时候会和旧项目有兼容问题。遇到依赖冲突时,不要盲目npm install到底,可以查看package.json确认版本,或者删掉node_modulespackage-lock.json后重新安装。

在一台干净的机器上装 Vue 环境时,Node.js 版本建议保持 18 以上,否则很多新库根本不支持。装完环境先跑一下默认模板,确认网络没问题,再接手项目代码。

6.2 axios 封装、Token 保存与请求拦截器

axios 是 Vue 项目里最常用的 HTTP 请求库。我习惯在src/utils/request.js里做一个统一封装,把所有重复逻辑收口:

import axios from 'axios' const request = axios.create({ baseURL: 'http://localhost:8000/api', timeout: 10000, withCredentials: true }) request.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers.Authorization = `Bearer ${token}` } return config }) request.interceptors.response.use( response => response.data, error => { if (error.response && error.response.status === 401) { localStorage.removeItem('token') window.location.href = '/login' } return Promise.reject(error) } ) export default request

在这个项目里,我们同时使用了 Django session 和自定义 token。withCredentials: true是为了让浏览器在跨域请求时带上 Cookie,保证 Django session 能正常识别用户登录状态。

6.3 路由守卫与登录状态判断

前端的登录状态判断是很多同学容易写错的地方。一个误区是只看 localStorage 里有没有 token,不看 token 是否过期。更完善的做法是在路由守卫里做一个“静默验证”:

router.beforeEach(async (to, from, next) => { const token = localStorage.getItem('token') if (to.path === '/login') { next() return } if (!token) { next('/login') return } try { const res = await request.get('/auth/profile') if (res.code === 0) { next() } else { localStorage.removeItem('token') next('/login') } } catch (e) { localStorage.removeItem('token') next('/login') } })

这样即使 token 过期,用户刷新页面后也会被自动踢到登录页,而不会出现“明明登录了,接口却一直 401”的诡异问题。

6.4 路由参数传递的典型写法

热词里提到“vue路由参数”,这个在前后端分离项目里很常见。比如管理员在用户列表点击某个用户进入详情页,需要传递用户 ID。

使用 Vue Router 4 的写法:

// 路由配置 { path: '/user/:id', component: UserDetail } // 跳转 router.push({ name: 'UserDetail', params: { id: 1 } }) // 在组件中获取 const route = useRoute() console.log(route.params.id)

需要注意的一个坑是:用params传参时,刷新页面后参数会丢失。如果信息重要,要把 ID 放到路由路径里,或者从后端重新拉取详情数据,不要依赖页面间的临时状态。

7. 上线部署:waitress + nginx 配合 Django 的方案与踩坑

7.1 开发环境跟生产环境最大的差异不在代码,在服务运行方式

很多同学的项目在本地用python manage.py runserver跑得飞起,一部署到服务器就出各种问题。原因很简单:runserver是 Django 自带的开发服务器,性能和稳定性都不适合生产环境。

网上有很多教程推荐用 gunicorn 部署 Django,但 gunicorn 在 Windows 服务器上支持不好。我们这台校园网服务器是 Windows Server,所以最终选择了 waitress,这是一个跨平台的纯 Python WSGI 服务器,Windows 和 Linux 都能稳定跑。

7.2 waitress 部署的基本配置

使用 waitress 前首先安装:

pip install waitress

然后在项目根目录创建一个wsgi.py或者直接用命令启动:

waitress-serve --listen=127.0.0.1:8000 config.wsgi:application

注意监听端口要跟 nginx 配置保持一致。这里我先监听127.0.0.1,目的是不让 Django 直接暴露在公网,而是通过前面的 nginx 做一层转发。

为了确保服务崩溃后能自动重启,我用了 Windows 的任务计划程序,或者直接在服务器上注册成 NSSM 服务,把 waitress 做成一个常驻后台服务。这样服务器重启后服务也能自动拉起,不需要人工登录服务器手动执行命令。

7.3 nginx 反向代理配置与静态文件收集

nginx 在项目中承担了两个任务:一是把来自 80 端口的请求转发给 Django,二是托管 Vue 打包后的静态文件和 Django 的静态资源。

一个最小配置示例:

server { listen 80; server_name auth.example.edu.cn; # Vue 前端打包文件 root /home/www/frontend/dist; index index.html; location / { try_files $uri $uri/ /index.html; } # API 反向代理到 Django location /api/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } # Django 静态文件 location /static/ { alias /home/www/django_static/; } }

这里的try_files $uri $uri/ /index.html是 Vue Router 使用 history 模式时的关键配置,不加这一行,用户手动刷新非首页路由时会 404。

7.4 静态文件显示不了这个经典问题的完整排查链路

热词里有“vscode写img标签 在django的static文件中显示不了”,我在这个项目里也遇到过,排查链路值得分享。

首先确认DEBUG = False后,Django 默认不会自动服务静态文件,必须先执行收集命令:

python manage.py collectstatic

这个命令会把所有 app 下的静态文件复制到STATIC_ROOT指定目录。

排查顺序是:

  1. 确认STATIC_URL是否正确,例如/static/
  2. 确认STATIC_ROOT是否配置成绝对路径
  3. 确认collectstatic是否执行成功,目录里有没有文件
  4. 确认 nginx 的location /static/是否正确指向STATIC_ROOT
  5. 直接访问http://ip/static/xxx.png看返回什么状态码

大部分情况下,问题都出在第二步和第四步的路径不一致。尤其是 Windows 服务器上路径可能带有盘符,nginx 的 alias 路径很容易配错。

8. 项目结束后的一些体会和可扩展方向

项目上线稳定运行了一段时间,我自己总结了几条真实体会,给后面做同类系统的朋友一个参考。

第一,认证系统这类项目,最容易翻车的地方不是认证本身,而是权限数据的前后端一致性。前端隐藏了菜单,后端接口也得拦,两边但凡有一个漏了,就等于没做权限。我们的做法是维护一张权限清单表,前端路由表和后端装饰器都从这张表里生成,减少人为不一致。

第二,校园网环境里用户量虽然不小,但并发峰值其实不高,真正卡脖子的往往是旧系统和乱七八糟的网络设备对接。做系统时一定要提前考虑协议对接的复杂度,给设备联动部分留足开发时间。

第三,这个小系统后续可以扩展的方向很多。热词里有人搜“vue播放m3u8”,其实就是典型的认证后资源访问场景:用户通过认证后才能访问特定的流媒体资源。接入一个视频资源服务时,只要在访问控制层加一个新的资源类型和权限点,前端拿到授权后用 vue-video-player 或者原生 video 标签播放 m3u8 流即可。认证和权限层搭建好之后,这些扩展都是比较顺理成章的事情。

我个人在实际操作中还有一个习惯,就是每完成一个阶段任务,都会把 PyCharm 里跑通的服务和 nginx 配置一起写成一份简单的部署文档。别小看这几百字文档,后来同事接手维护时,全靠它省下了大量重复排查时间。做这类系统,代码只是其中一部分,让别人能接手、敢维护,才算是真正交付完成。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询