☰
统一身份认证服务毕设实战:基于Python与JWT的SSO单点登录实现
2026/10/1 4:48:08 网站建设 项目流程

1. 为什么把"统一身份认证服务"做成毕设

1.1 一个场景说清楚它到底解决什么问题

先别被"统一身份认证服务"这个名字吓住,它背后解决的问题,你几乎每天都在经历。

想象你的学校或单位同时跑着好几套系统:教务系统、图书借阅系统、邮箱系统、内部办公系统。正常运营模式下,每个系统都各建一套账号密码,于是你手机密码本里躺着五六个账号,密码规则还不统一,有的要求大小写字母加数字,有的必须带特殊符号。你登录一次,基本要把所有密码轮番试一遍。

更要命的是系统之间的联动。比如你要打印一份教务处的课表,先登录教务处网站下载文件,再登录打印管理系统上传。两个系统彼此不认识,你得重复提交两次身份信息。忘密码的时候更崩溃,每个系统都要单独走一遍找回流程,体验差到极点。

统一身份认证就是为了解决这个"账号林立、身份割裂"的痛点。它的核心思路很朴素:把"判断用户身份"这件事单独抽出来,做成一个独立服务,所有业务系统都通过它来确认用户是谁。用户只要在统一的认证中心登录一次,再访问其他系统就不需要重复登录了。这个体验在行业里叫SSO(Single Sign-On,单点登录),你在很多"一次登录,处处可用"的网站上实际体验过。

把这个场景放进毕设非常合适,因为需求一点都不虚,每个人都能理解,而且答辩评委大概率也是这套系统的日常使用者,他一看就知道你做的是什么。

1.2 这个题目凭什么值得写

选毕设题目,很多人有个误区:以为功能堆得越多越好,于是做一个"XX管理系统",把增删改查铺成十个页面。这种项目写起来快,但答辩时讲不出深度,因为里面只有"是什么",没有"为什么"。

统一身份认证服务不一样,它自带清晰的设计逻辑,天然能讲出层次。

第一,它覆盖一条完整的技术链路。最小可用的认证服务,至少包含前端登录页、后端接口、数据库设计、密码加密、Token签发与校验、跨域配置、登录日志。这一路走下来,前后端交互、网络请求、数据存储这些基本功全被激活,比闷头写页面扎实得多。

第二,它有很强的架构感。业务系统怎么接入认证中心,登录成功后怎么跳转回来,Token失效了怎么处理,用户被强制下线怎么通知业务系统,这些问题全都要设计,不是Ctrl+C、Ctrl+V能糊弄过去的。论文的"系统设计"章节可以画架构图、时序图、数据流图,篇幅和深度直接拉满。

第三,它的扩展性极强。同样是"统一身份认证"这个内核,你可以用Python做,也可以用Java、PHP做;你可以做Web版,也可以接小程序和App;你甚至可以把登录日志做成数据可视化大屏,或者写一个自动化的认证脚本配合爬虫做数据采集。项目标题里那一串"JAVA、PHP、爬虫、APP、小程序、C#、C++、python、数据可视化",其实都能从这个主题延伸出去。

第四,它和真实生产环境是接轨的。去看看招聘市场,身份认证、权限管理、单点登录这些关键词,几乎出现在每一个后端岗位的需求里。毕设做了这个,面试时至少有一个真实项目可以聊,而且是一个能讲清原理、有技术亮点的项目。

2. 核心方案选型:动手前必须想清楚的几件事

2.1 状态方案:用Session还是Token

在写第一行代码之前,最该先想明白的是:用户登录成功后,业务系统怎么识别"这个人是谁"。

老一套做法是Session。流程大概是:用户在登录页面输入账号密码,服务器验证通过后,在服务器内存里创建一条会话记录,生成一个Session ID,通过Cookie返回给浏览器。之后浏览器每次请求都自动带上这个Cookie,服务器查一下Session ID,就知道用户是谁了。

这套方案在早期单体应用里很流行,实现也简单,但它有几个对统一身份认证这种多系统场景几乎是致命的缺点。首先是服务器状态共享问题,如果你部署了两台服务器,用户在A服务器登录了,请求被负载均衡转到B服务器,B服务器内存里没有这个用户的Session,就会判定未登录。解决办法是把Session集中存到Redis或数据库里做共享,但这就等于又引入了外部依赖和额外的转移开销。其次是跨域问题,Cookie默认受同源策略限制,认证中心和业务系统大概率不在同一个域名下,你得一直处理跨域、Cookie携带这些琐碎问题,非常磨人。

Token方案的思路完全不同。服务器验证用户密码后,不发Session ID,而是发出一串结构化的字符串——Token,用户把Token保存在前端,每次请求放到请求头里发给服务器,服务器通过解密和签名校验来确认Token是否有效。服务器不存任何用户状态,所以叫"无状态认证"。

我做这个毕设时,毫不犹豫选了Token方案。原因很简单:认证中心和多个业务系统是"一对多"的关系,业务系统根本不需要记住任何会话,只需要会验证Token的签名就够了。打个比方,就像健身房办年卡,入场前台给你发一个带防伪标志的手环,你进每个器械区,工作人员只要看一眼手环上的标志就能放行,不需要打电话回前台问"这人到底办卡了没"。

2.2 具体落地:JWT令牌的内部结构

Token是个抽象概念,真正落到代码里,最常用的标准格式是JWT(JSON Web Token),也是我这个项目里的选择。

JWT长什么样?它是一串由两个点分隔成三段、经过Base64编码的字符串,格式是"头部.载荷.签名"。猛一看是乱码,拆开看每部分都很清晰。

头部(Header)声明两个信息:令牌类型是JWT,签名算法用什么,比如HS256(HMAC-SHA256)或者RS256(RSA-SHA256)。载荷(Payload)放的是真正的业务数据,常见的有用户ID、用户名、过期时间(exp)、签发时间(iat),还可以塞自定义字段,比如用户角色。签名(Signature)是拿前两段编码结果加一个密钥计算出来的,作用就是防篡改:任何人改动载荷里的用户ID,签名校验立刻失败,服务器直接拒绝。

这里有个关键点,JWT本身不依赖服务器保存状态,业务系统拿到Token后,只要本地验证签名有效、检查过期时间没过,就能确认用户身份。这就是为什么业务系统接入认证中心时,不需要在自己的数据库里同步任何用户会话数据。

HS256和RS256的区别需要留意一下。HS256用同一个密钥进行签名和验签,所以所有业务系统和认证中心必须共享一个密钥,适合小规模、可控的场景;RS256用私钥签名、公钥验证,认证中心专门保管私钥负责签发,业务系统只持有公钥负责验证,适合更分散的架构。毕设里用HS256完全没问题,但答辩时如果能提一句"正式环境我更推荐RS256",印象分会好不少。

2.3 登录全流程:一次SSO是怎么跑通的

方案定了,接着要设计流程。一个标准的、基于JWT的单点登录流程,我习惯拆成四步去理解。

第一步,用户访问业务系统A。A的前端发现本地没有Token,就把用户重定向到认证中心的登录页。这一步通常带一个回调地址参数,告诉认证中心"验完身份后,把人送回哪个地址"。

第二步,用户在认证中心输入账号密码。认证中心验证密码正确后,做两件事:一是在认证中心域名下种下一个"已登录"的标记(一般是签过名的Cookie),二是生成一个一次性的授权码Code,然后让用户带着这个Code重定向回业务系统A的回调地址。

第三步,业务系统A的后端收到这个Code,拿它去调用认证中心提供的"换取Token"接口。认证中心验证Code有效,就返回正式的JWT。这里的关键设计是:Code只能使用一次,有效期极短,防止中途被劫持复用。

第四步,业务系统A的前端拿到JWT,之后的每次请求都带上它。当用户后来又去访问同样纳入认证体系的业务系统B时,B发现没有Token,也会跳转认证中心。但认证中心一看用户已经登录过了(第二步种下的Cookie还在),就不会再要求输密码,而是直接生成Code送回业务系统B,B再拿着Code换Token,流程走一遍但用户无感知。

这个流程里最核心的一句话是"认证中心兜底"。所有业务系统都不自己比对账号密码,只信任认证中心的校验结果。这也正好回答了一个很多同学会问的问题:为什么我不能在一台服务器上登录后,另一台服务器直接用同一个Token?因为Token本身就是答案,你不需要跨服务器同步任何东西,大家都能验同一套签发的Token。

2.4 数据表设计:不复杂但要想清楚

我设计库表时,没有铺太多表,核心就四张。

用户表(user)存账号、密码哈希值、盐值、昵称、状态(正常/锁定)、创建时间。密码绝对不能存明文,这是我反复强调的一点,后面会展开。

客户端应用表(app_client)存每个接入方的基本信息,比如应用名称、应用ID、应用密钥、回调地址白名单。这个表的意义是让认证中心知道"谁有资格接入",并且在换取Token时校验回调地址是否在白名单内,防止别人伪造回调。

授权码表(auth_code)在真正的生产环境里通常不落库,而是放Redis并设置极短过期时间,但如果你不想在毕设里引入Redis,也可以暂时用数据库表实现,字段就是授权码、关联用户ID、关联客户端ID、过期时间、是否已使用。它的核心约束是"一次性",用过即失效。

登录日志表(login_log)记录谁在什么时间什么IP登录了,这是后面做数据可视化、做安全审计的数据来源。字段建议包含用户ID、登录时间、IP地址、登录结果、失败原因。

这套表结构看起来简简单单,但把认证中心需要承担的责任都落实了:管用户、管接入方、管临时凭证、留审计记录。

3. 用Python实现认证中心的完整过程

3.1 技术栈:Flask + PyJWT + Redis

Python做Web后端,主流选择是Flask和Django。我选Flask,核心原因是认证服务本身功能边界清晰,不需要Django那一整套自带的管理后台、ORM、模板引擎,Flask轻量灵活,写起来更直观。尤其是毕设阶段,代码量不大,Flask的短小精悍能让你把注意力放在认证逻辑本身。

配套组件里,PyJWT是专门用来生成和校验JWT的库,接口简单,文档清楚,省去自己实现签名算法的麻烦。Redis在这个项目里有两个用途:一是存授权码,设置几十秒过期,天然支持过期删除;二是维护Token黑名单,用户登出后把Token塞进黑名单,设置与Token剩余寿命一致的过期时间,就能实现"登出即失效"。

如果你本地没装Redis,Windows上可以用Memurai,或者干脆直接在代码里用字典加时间戳实现一个简易版,但正式演示时我建议还是把Redis跑起来,答辩时可以多讲一句"用Redis管理短期凭证和黑名单,避免频繁写数据库",这也是一个加分点。

3.2 用户登录接口与密码存储

先看密码存储。这是整个系统安全性的地基,也是最容易被人挑刺的点。

正确做法是加盐哈希存储。给每个用户的密码拼上一段随机生成的盐值,再用不可逆的哈希算法处理。推荐用bcrypt或者PBKDF2,Python里可以直接用werkzeug.security这个工具包,它内置了generate_password_hash和check_password_hash,底层就是加盐哈希,用起来很方便。

from werkzeug.security import generate_password_hash, check_password_hash # 注册时:生成哈希并存储 hashed = generate_password_hash("用户输入的明文密码") # 保存 hashed 到数据库,注意不要再保存明文 # 登录时:比对哈希 is_ok = check_password_hash(hashed, "用户再次输入的明文密码")

登录接口的逻辑并不复杂,整体流程是:前端提交账号密码,后端先查用户是否存在、状态是否正常,然后用check_password_hash比对密码,比对成功就把用户ID和登录时间组装进JWT,生成Token返回给前端。

from flask import Flask, request, jsonify import jwt import datetime app = Flask(__name__) SECRET_KEY = "your-secret-key-change-me" @app.route("/api/login", methods=["POST"]) def login(): data = request.get_json() username = data.get("username") password = data.get("password") # 查询用户、校验密码(代码省略,取到 user 对象) user = find_user_by_username(username) if not user or not check_password_hash(user.password_hash, password): return jsonify({"code": 401, "msg": "账号或密码错误"}), 401 payload = { "user_id": user.id, "username": user.username, "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=2) } token = jwt.encode(payload, SECRET_KEY, algorithm="HS256") return jsonify({"code": 200, "token": token})

有几个细节我要专门提醒。第一,生产环境绝对不能用固定的硬编码密钥,我这个例子里写了占位符,你自己的项目里至少要用一个安全随机生成的长字符串,并且代码里只放到配置文件中。第二,登录接口一定要做频率限制,防止别人拿字典爆破密码,最简单的做法是同一个IP或者同一个账号一分钟内最多尝试5次,超出就锁一段时间。第三,返回给前端的Token不要放在URL参数里,浏览器历史会记录,泄露风险很高,正确做法是放在响应体里由前端存起来,后续请求放进请求头。

3.3 Token校验接口:业务系统最依赖的入口

业务系统接入认证中心,核心要调用的就是Token校验接口。它的作用很简单:收到业务系统传来的Token,校验签名、校验过期时间、校验是否在黑名单里,然后返回这个Token对应的用户信息。

from functools import wraps def verify_token(token): try: payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"]) except jwt.ExpiredSignatureError: return None, "token已过期" except jwt.InvalidTokenError: return None, "token无效" # 检查黑名单(省略 Redis 查询逻辑) if is_in_blacklist(token): return None, "token已失效" return payload, None @app.route("/api/verify", methods=["POST"]) def verify(): token = request.headers.get("Authorization", "").replace("Bearer ", "") payload, err = verify_token(token) if err: return jsonify({"code": 401, "msg": err}), 401 user = find_user_by_id(payload["user_id"]) return jsonify({ "code": 200, "user_id": user.id, "username": user.username })

这个接口设计成POST而不是GET,是因为GET请求容易被日志系统或浏览器插件记录下来,Token通过POST的请求体传递更安全。业务系统调用时,把JWT放在Authorization请求头里,这是一种约定俗成的标准用法。

这里顺便讲一下为什么业务系统本地就能校验Token,却还要调接口。实际上很多轻量接入方确实可以只在本地用公钥验签,不需要每次请求都来问认证中心,这样性能更好。但毕设项目里保留一个verify接口意义在于:一是演示起来更直观,二是黑名单机制必须有这个入口,三是如果Token里携带的权限信息需要实时更新,集中校验更方便。你可以把两种方式都写在文档里,说明各自的适用场景,这会显得你对方案的理解更透彻。

3.4 模拟两个业务系统的SSO演示

很多人做完认证中心,不知道怎么演示单点登录的效果。我的经验是用两个简单的前端页面模拟业务系统,分别跑在不同的端口,一个8001叫"教务系统",一个8002叫"图书系统"。

用户先访问8001,页面弹提示"未登录",自动跳转到认证中心地址(比如5000端口)。用户在认证中心登录成功后,被重定向回8001,8001的后端拿着Code换到Token。此时页面显示当前登录用户,并能调用一个受保护接口返回模拟数据。

接着不关闭浏览器,直接访问8002,你会发现系统没有要求重新登录,而是直接进入了已登录状态。这个"无感登录"的过程,就是整个项目最惊艳的演示点。

实现这个效果时,最需要注意的是授权码的流转。业务系统后端拿到Code后,要带上自己的应用ID和应用密钥,再调用认证中心的换Token接口,这一步一定要由后端完成,绝不能在前端完成,否则应用密钥会暴露在浏览器里,任何人都有机会冒充业务系统。

为了让答辩更生动,还可以在认证中心加一个"已登录应用"列表,显示当前会话登进过哪些系统。这样用户访问8001和8002后,回到认证中心看到两个系统的登录记录,整个SSO链路就形成了闭环,一眼就能看懂。

3.5 登出与Token失效处理

登出功能看似简单,其实也有讲究。我的方案是:认证中心提供一个登出接口,把当前Token加入Redis黑名单,同时清掉认证中心域名下的登录Cookie。

@app.route("/api/logout", methods=["POST"]) def logout(): token = request.headers.get("Authorization", "").replace("Bearer ", "") payload, _ = verify_token(token) if payload: # 将 token 加入黑名单,过期时间与 token 剩余时间对齐 remaining = payload["exp"] - int(datetime.datetime.utcnow().timestamp()) add_to_blacklist(token, remaining) return jsonify({"code": 200, "msg": "登出成功"})

为什么登出后还要保留Token直到它自然过期,而不是立刻让它失效?因为JWT是无状态的,认证中心无法主动通知所有业务系统"这个用户登出了",所以只能通过黑名单机制来"临时禁用"。把黑名单的过期时间设置成与Token剩余寿命一致,既保证登出后Token立即不可用,又不会让黑名单无限膨胀占内存。

真正要全局踢人下线,更彻底的做法是在用户表里加一个token_version字段,每次生成Token时把版本号写进载荷,校验时对比数据库里的当前版本,版本不一致就拒绝。这种方法适合"修改密码后踢掉所有旧会话"、"管理员强制下线某个用户"这类场景。毕设里能做到登出进黑名单已经很不错,如果再把版本号方案提一嘴,就属于超纲加分了。

4. 实操中的常见问题与排坑记录

4.1 跨域问题:认证中心和业务系统不是一家人

跨域是这类多系统项目里最容易把人卡住的问题,而且报错信息对新手很不友好,浏览器控制台里一串英文,实际含义就是"你的浏览器拒绝这个请求携带身份信息"。

认证中心在5000端口,业务系统在8001端口,前端从8001页面发起向5000的请求,端口不同就是跨域。解决思路分两层。第一层是后端允许跨域,在Flask里用flask-cors库配置允许的域名和请求头,注意Authorization请求头必须显式加进allowed_headers,否则前端带Token的请求依然会被拦。第二层是Cookie的SameSite属性,如果SSO依赖Cookie判断已登录状态,跨域场景下浏览器可能直接把Cookie丢掉,需要把SameSite设置为Lax或者None,但设置了None就必须配合Secure属性,也就是只在HTTPS下生效,开发环境可以用localhost来绕过。

我踩过的坑是:在本地环境用127.0.0.1调试时一切正常,换成localhost就出问题。原因是Cookie的Domain匹配机制把IP和域名当成两个不同的源。建议从一开始就统一用localhost访问所有服务,省掉一整类莫名其妙的问题。

4.2 前端要做的三件事:保存、携带、刷新

很多同学做完后端接口,发现前端不知道怎么配合。这里有个基本功得理顺。

第一步,前端收到登录接口返回的Token后,存到localStorage或sessionStorage里,注意不要存到Cookie里,否则又会引入CSRF(跨站请求伪造)风险。第二步,封装统一的请求工具,在发起每个请求时从存储里取出Token,放到请求头:

const token = localStorage.getItem("token"); fetch("/api/user_info", { headers: { "Authorization": `Bearer ${token}` } });

第三步,处理Token过期。JWT设置了两小时过期,用户用了一个半小时后请求接口,返回401,这时前端要捕获这个状态,自动跳转到认证中心重新登录,而不是弹一个让人摸不着头脑的报错框。比较体面的做法是加一个Refresh Token机制:访问Token过期了,用Refresh Token去换新的访问Token,用户无感知。但Refresh Token本身也需要安全存储和复用限制,毕设里如果做不好,建议老实做"过期就重新登录"就好,至少体验一致、逻辑闭环。

4.3 安全细节:密码、防刷、防泄露

这个项目最容易被答辩老师翻来覆去问的就是安全问题,提前准备几个标准答案有备无患。

密码存储,上面说过,必须加盐哈希,绝不允许明文。这一点是底线,老师一问"你的密码库泄露了怎么办",如果你回答"我用的bcrypt加盐哈希,即使用户密码库被拖走,破解单个密码的成本也非常高",场面就稳了。

接口防刷,登录接口必须限流。最简单的实现是Redis里存一个计数器,键名是"login:尝试次数:用户名+IP",一分钟内超过5次就拒绝并提示"尝试次数过多,请稍后再试"。这能有效挡住低成本的暴力破解。

Token防泄露,后端统一在所有响应头上加Cache-Control: no-store,防止浏览器缓存包含Token的页面;前端不要在任何URL参数里传Token;所有会话相关的接口建议走HTTPS。虽然是毕设,但你在文档里写明这些点,答辩水平立刻和其他"能跑就行"的项目拉开差距。

关于日志和隐私,不要记录密码、Token等敏感字段,只记录登录结果和IP,也顺便回应了"最小化数据收集"的通用要求。

4.4 一套好用的排错思路

多系统协作的项目,出问题后第一反应很重要。我的建议是"从近到远、逐层排查"。

前端报401,先看请求是不是真的带上了Authorization头,再确认Token是不是过期了,最后把Token放到jwt.io这类工具上检查签名算法是否符合预期。前端跳转到认证中心后一直回不来,优先检查回调地址参数是否编码正确,认证中心返回给业务系统时是否仍然用同一个回调地址。业务系统换Token换不到,检查应用ID和应用密钥是否配对、认证中心白名单里有没有登记这个回调地址。

只要养成"看请求、看响应、看日志"三步走的习惯,大部分问题能在十分钟内定位。我在做这个项目时,最常用的就是浏览器的开发者工具,F12打开网络面板,把每个请求的请求头、响应体看一遍,问题基本就水落石出了。

5. 怎么把同一个题目扩展到其他方向

5.1 换语言实现:Java和PHP的思路

很多学校要求毕设必须用Java,或者你手头只会PHP,其实完全不用慌。统一身份认证的核心是思路,不是语言,同一个方案可以平移。

Java首选Spring Boot加Spring Security,天然支持OAuth2和JWT。你甚至不需要自己手写JWT签发,用spring-security-oauth2-jose和spring-security-oauth2-resource-server就能把认证中心和资源服务搭出来,代码量比Python版更少。答辩时还能讲一嘴Spring Security的过滤器链机制,这属于加分项。

PHP的话,用Laravel的Passport包或者直接用原生PHP配合firebase/php-jwt这个库也很方便。Laravel自带用户认证体系,改造一下登录返回逻辑就能签发JWT。如果学校允许原生PHP,就自己写一个Token工具类,原理完全相同。

换语言时最需要移植的其实是三样东西:JWT签发与校验逻辑、密码哈希存储逻辑、授权码的生成与一次性消费逻辑。把这三点想透了,任何一门后端语言都能写出认证中心。

5.2 接App、小程序和数据可视化

如果毕设题目挂的是"App"或"小程序",统一身份认证依然能升级复用。

App端和Web端最大的区别是,没有浏览器帮你管理Cookie和跳转,所以App通常采用纯Token方案:用户在登录页输入账号密码,认证中心返回Token,App持久化保存,后续所有请求带上Token。如果想做扫码登录,额外加一个轮询逻辑:App扫描认证中心展示的二维码,二维码里带上一个临时标识,App确认登录后,认证中心把会话标记为已确认,浏览器端轮询到已确认就跳转。这个功能看起来高级,实际实现也就增加两个接口。

小程序端更特殊,微信自己有wx.login体系,但毕设完全可以做成自建账号体系,流程和App一致,只是请求工具换成wx.request。数据可视化就更好接了,把登录日志里的用户ID、登录时间、IP地址,按小时、按系统维度做聚合统计,用ECharts或者Python的Flask加一个前端页面展示活跃趋势图。我见过最讨巧的做法是做一个"认证中心运营大屏",左侧登录趋势折线图,右侧各系统接入情况饼图,中间滚动最近登录记录,整体效果非常唬人,做起来却一点也不难。

5.3 和爬虫结合:给自动化采集做一个正规入口

项目标题里出现了"爬虫",很多人第一反应是"Scrapy框架、requests库、网页解析",但这些和统一身份认证有啥关系?实际上是有的,而且关系很自然。

很多数据采集场景,不是爬公开网页,而是要采集需要登录才能看到的数据。在没有认证服务时,你只能模拟登录、硬啃加密参数、和反爬机制斗智斗勇。如果项目里有统一身份认证,你可以把它当做一个合法的"身份获取入口":先用账号密码调用认证中心的登录接口拿到Token,再拿这个Token去请求业务系统的数据接口,整个采集过程就走上了正规、可控的路径,不需要逆向任何加密参数,也大大减少了被反爬机制误伤的概率。

需要强调的是,这种用法只适用于你有合法授权的情况,比如你自己的项目、内部系统的数据归集。做毕设也罢、做研究也罢,采集之前一定要搞清楚数据的使用边界,遵守网站的服务条款和robots协议,不做任何越权的尝试。把"通过认证中心统一获取身份凭证再访问数据接口"这个设计放在论文里,导师会觉得你考虑的不仅是技术,还有工程规范,印象分会更好。

5.4 论文和演示录像怎么做出彩

最后说点答辩实用技巧,毕竟很多同学做完系统,不知道怎么在论文和演示环节把亮点讲足。

论文结构上,我建议至少保证这些内容:背景与意义里写清"多系统账号孤岛"的痛点,核心技术和相关研究里把JWT、单点登录、OAuth2这些概念的演变讲清楚,系统设计章节放架构图、数据库ER图、接口时序图,实现章节按模块写并配核心代码片段,测试章节记录功能测试和安全测试的结果。论文里不需要贴完整代码,但一定要有"设计思路"的说明文字,这比代码本身更能体现工作量。

演示录像我踩过的坑是:录屏时忘了先把服务全部启动好,结果边录边等启动,观众体验很差。正确流程是:先启动认证中心、两个业务系统、Redis,全部就绪后再开录。录的时候按这个顺序走:首页介绍项目背景,展示数据库表,然后演示未登录访问被重定向、登录成功回跳、跨系统无感登录、登出后Token失效,最后补一个安全测试画面(错误密码连续输入被锁定)。全程控制在六分钟内,节奏紧凑,比拖沓的十几分钟效果好得多。

还要提醒一句,演示时准备一个干净的测试账号,密码设置得简单一点,避免现场输入错误导致尴尬。如果现场网络不稳定,优先把Redis、MySQL都切到本地模式,不要让演示依赖外网。

6. 最后再分享一点我的经验

我在实际做这类认证项目时,最大的体会是:校内的毕设题目,真正拉开差距的不是功能数量,而是边界意识。

统一身份认证这种题目,功能列表可以无限长——验证码、扫码登录、短信登录、第三方OAuth接入、权限管理、审计报表,样样都能加。但一个合格的毕设核心不是堆功能,而是把你选定的那几条链路做到闭环、做得严谨。登录、校验、登出、授权码交换这四个核心环节,每一个的异常情况都要处理到位,比多做一个花哨页面重要得多。

同样值得说的是,千万不要直接拿现成源码跑通了就算完事。白嫖的源码可以供你参考,但如果你在答辩时连自己项目里的SECRET_KEY放在哪个文件、黑名单为什么用Redis、业务系统为什么不能直接拿用户密码这些基础问题都答不上来,老师一眼就能看出来。安全的做法是:参考别人的源码,理清思路,再把核心模块自己重写一遍,尤其是JWT签发与校验、授权码交换这两个环节,用你自己的语言和风格来实现。

我个人一直觉得,毕设最理想的状态不是做出来一个完美无可挑剔的产品,而是把你做过的每一个技术决定都能说出理由。统一身份认证恰恰给了你这样的空间:为什么用Token不用Session,为什么授权码要用一次性的,为什么业务系统不能直接碰密码,这些问题没有标准答案,但每个都对应一条清晰的技术逻辑。你把这个逻辑讲通了,分数自然不会低。

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

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

立即咨询