用 FastAPI 写求职者登录注册
用 FastAPI 写求职者登录注册这是一个仿 BOSS 直聘项目的后端模块技术栈是 FastAPI MySQL Redis 阿里云 OSS。下面按代码结构记录求职者登录注册这块怎么写。数据库表 models文件 app/models/job_seeker.py用 ORM 建表就是写一个 Python 类fromtortoise.modelsimportModelfromtortoiseimportfieldsclassJobSeeker(Model):idfields.IntField(pkTrue)mobilefields.CharField(max_length20,uniqueTrue)# 手机号不能重复passwordfields.CharField(max_length255,nullTrue)avatarfields.CharField(max_length500,nullTrue)# 存头像图片网址nicknamefields.CharField(max_length100,nullTrue)emailfields.CharField(max_length100,nullTrue)wechatfields.CharField(max_length100,nullTrue)create_timefields.DatetimeField(auto_now_addTrue)update_timefields.DatetimeField(auto_nowTrue)classMeta:tablet_job_seekeruniqueTrue 表示手机号不能重复nullTrue 表示可以为空auto_now_add 和 auto_now 让数据库自动记录注册时间和修改时间。参数校验 schemas文件 app/schemas/job_seeker.py前端传来的数据用 Pydantic 定规矩Field(…) 表示必传frompydanticimportBaseModel,FieldclassLoginMobileRequest(BaseModel):mobile:strField(...,title手机号)password:strField(...,title密码)classLoginSmsCodeRequest(BaseModel):mobile:strField(...)code:strField(...)classCreateUserRequest(BaseModel):mobile:strField(...)password:strField(...)code:strField(...)classUpdateUserRequest(BaseModel):mobile:strField(...)new_password:strField(...)code:strField(...)漏传的话 FastAPI 会自动报错不用自己处理。业务逻辑 services文件 app/services/job_seeker.py先准备两个工具importredis redis_clientredis.Redis(hostlocalhost,port6379,db6,decode_responsesTrue)importrandomdefget_random_code(length6):return.join(random.choices(1234567890,klength))手机号密码登录asyncdeflogin_by_mobile_password(req):jobseekerawaitJobSeeker.get_or_none(mobilereq.mobile)ifjobseekerisNone:raiseException(手机号不存在)ifjobseeker.password!req.password:raiseException(密码错误)access_token,refresh_tokencreate_tokens(str(jobseeker.id),jobseeker.mobile)return{jobseeker:jobseeker,access_token:access_token,refresh_token:refresh_token}这里密码是明文对比的练手可以正式项目要加密存储。发送登录验证码asyncdefsend_sms_code(mobile):jobseekerawaitJobSeeker.get_or_none(mobilemobile)ifjobseekerisNone:raiseException(手机号不存在)codeget_random_code(6)redis_client.set(fboss-api:login:sms:{mobile},code,ex120)returncode验证码存进 Redis120 秒后自动过期。return code 是为了方便测试正式项目应该调用短信服务发到手机。验证码登录asyncdeflogin_by_mobile_code(req):jobseekerawaitJobSeeker.get_or_none(mobilereq.mobile)ifjobseekerisNone:raiseException(手机号不存在)redis_coderedis_client.get(fboss-api:login:sms:{req.mobile})ifredis_codeisNone:raiseException(验证码已过期)ifredis_code!req.code:raiseException(验证码错误)access_token,refresh_tokencreate_tokens(str(jobseeker.id),jobseeker.mobile)redis_client.delete(fboss-api:login:sms:{req.mobile})return{jobseeker:jobseeker,access_token:access_token,refresh_token:refresh_token}先取 Redis 里的验证码过期或错误就报错通过后发 token 并删掉验证码。注册发注册验证码asyncdefsend_sms_code_create(mobile):codeget_random_code(6)redis_client.set(fboss-api:create:sms:{mobile},code,ex120)returncode正式建号asyncdefcreate_job(req):redis_coderedis_client.get(fboss-api:create:sms:{req.mobile})ifnotredis_code:raiseException(验证码已过期)ifredis_code!req.code:raiseException(验证码错误)ifawaitJobSeeker.get_or_none(mobilereq.mobile):raiseException(手机号已存在)new_jobseekerawaitJobSeeker.create(**dict(req))redis_client.delete(fboss-api:create:sms:{req.mobile})access_token,refresh_tokencreate_tokens(str(new_jobseeker.id),new_jobseeker.mobile)return{msg:注册成功,access_token:access_token,refresh_token:refresh_token}注册的 Redis key 用 boss-api:create:sms:登录用 boss-api:login:sms:两者分开互不干扰。JobSeeker.create(**dict(req)) 把前端参数直接变成一条新记录注册完直接发 token。忘记密码asyncdefforget_password(req):redis_coderedis_client.get(fboss-api:login:sms:{req.mobile})ifnotredis_code:raiseException(验证码已过期)ifredis_code!req.code:raiseException(验证码错误)jobseekerawaitJobSeeker.get_or_none(mobilereq.mobile)ifjobseekerisNone:raiseException(手机号不存在)jobseeker.passwordreq.new_passwordawaitjobseeker.save()# 改了一定要 save不然不会存进数据库redis_client.delete(fboss-api:login:sms:{req.mobile})return{msg:修改密码成功}上传头像asyncdefupdate_avatar(job_seeker_id,file):contentawaitfile.read()ossAliyunOSSTool()ok,resoss.upload_single_file(content,file.filename,oss_pathjob_seeker_avatar/)ifok:jobseekerawaitJobSeeker.get_or_none(idjob_seeker_id)jobseeker.avatarres[access_url]awaitjobseeker.save()returnresraiseException(上传失败)图片传到 OSSOSS 返回图片网址只把这个网址存进 avatar 字段。查看资料asyncdefget_job_seeker_info_by_id(job_seeker_id):jsawaitJobSeeker.get_or_none(idjob_seeker_id)js.nicknamef用户{js.mobile}ifjs.nicknameisNoneelsejs.nickname js.avatar默认头像网址ifjs.avatarisNoneelsejs.avatarreturnjs昵称和头像为空时给默认值。接口 apis文件 app/apis/job_seeker_api.pyservice 写好后包成接口网址job_seeker_router.post(/login_by_mobile_password)asyncdeflogin_by_mobile_password(req:LoginMobileRequest):resawaitJobSeekerService.login_by_mobile_password(req)return{code:1,message:登录成功,data:res}接口层只做三件事收参数、调 service、包成统一格式返回。返回格式 code 为 1 成功 0 失败message 是提示data 是数据。全部接口前缀 /job_seeker/login_by_mobile_password 密码登录/send_sms_code/{mobile} 发登录验证码/login_by_mobile_code 验证码登录/send_sms_code_create/{mobile} 发注册验证码/create_job 注册/forget_password 忘记密码/me 查看资料需登录/update_avatar 换头像需登录登录状态 JWT登录成功后发 token之后每次请求带上服务器验证就知道是谁。defcreate_tokens(user_id,username):payload{user_id:user_id,username:username,type:access}payload[exp]datetime.utcnow()timedelta(minutes120)access_tokenjwt.encode(payload,SECRET_KEY,algorithmHS256)rpayloadpayload.copy()rpayload[type]refreshrpayload[exp]datetime.utcnow()timedelta(days7)refresh_tokenjwt.encode(rpayload,SECRET_KEY,algorithmHS256)returnaccess_token,refresh_tokenaccess_token 有效期 2 小时每次请求都带refresh_token 有效期 7 天用来换新 token。app/core/depends.py 里从请求头取 token 并解析出 user_iddefget_job_seeker_info(authorization:strHeader(None)):ifnotauthorization:raiseException(请登录)tokenauthorization.replace(Bearer ,)payloadverify_token(token)ifpayloadisNone:raiseException(验证失败)returnpayload[user_id]需要登录的接口加 Depends(get_job_seeker_info)FastAPI 自动先验证并把 user_id 传进来job_seeker_router.get(/me)asyncdefget_me(job_seeker_idDepends(get_job_seeker_info)):jsawaitJobSeekerService.get_job_seeker_info_by_id(job_seeker_id)return{code:1,message:获取成功,data:js}统一异常处理service 里 raise 的异常由全局处理器接住转成统一返回defglobal_exception_handler(request,exc):returnJSONResponse(status_code500,content{code:0,message:str(exc)})在 main.py 注册app.add_exception_handler(Exception,global_exception_handler)小结把这块写完后端常用的建表、参数校验、分层、JWT 登录、Redis 存验证码、OSS 存图片、统一报错都接触到了。建议跟着敲一遍把遇到的报错自己解决掉。正式上线前还要注意密码加密、验证码真发短信、发码接口加限流。

相关新闻

从零部署阿拉德源码:Linux服务端与Unity客户端联调实战

从零部署阿拉德源码:Linux服务端与Unity客户端联调实战

1. 项目概述与核心价值 最近在游戏开发圈里,一个基于经典端游《地下城与勇士》的“阿拉德源码”项目热度不低。很多朋友拿到源码后,面对Linux服务端部署这个环节就卡住了,特别是Unity 5.6.3这个特定版本的客户端与C服务端在CentOS 7.6环境下…

2026/10/2 13:24:04 阅读更多 →
微信聊天记录语音导出成音频文件全攻略:5种方法测评,最后一种亲测有效

微信聊天记录语音导出成音频文件全攻略:5种方法测评,最后一种亲测有效

想翻出半年前的一条语音,发现聊天记录已清空;想保存家人的语音消息,却不知道怎么导出;打官司需要语音证据,微信根本不给你导出入口。​微信语音,大概是数字时代最"脆弱"的记忆载体——存在于手机…

2026/10/9 22:28:55 阅读更多 →
Unity技能编辑器开发实战:架构设计、性能优化与常见问题解决

Unity技能编辑器开发实战:架构设计、性能优化与常见问题解决

1. 项目概述:Unity-SkillEditor的定位与核心价值在Unity项目开发中,尤其是涉及角色扮演、动作对战或策略类游戏时,技能系统的设计与实现往往是技术攻坚的重中之重。一个直观、高效且可维护的技能编辑器(SkillEditor)能…

2026/10/3 6:16:52 阅读更多 →

最新新闻

Unity编辑器底层机制与运行时原理详解

Unity编辑器底层机制与运行时原理详解

1. 别被“基础”两个字骗了:为什么Unity新手常在第3小时就卡死在编辑器里很多人点开Unity安装包时,心里想的是“不就是拖拖拽扭、放放模型、点点播放键吗”,结果三小时后盯着控制台里一串红色报错发呆——“NullReferenceException: Object r…

2026/10/14 8:50:30 阅读更多 →
国产AI算力地基:Runtime/Compiler/Driver三位一体开源框架

国产AI算力地基:Runtime/Compiler/Driver三位一体开源框架

1. 这不是模型发布,而是一次算力基建的静默升级 “致敬,DeepSeek 最新开源的不是模型,是国产算力的地基”——这句话在技术圈刷屏时,我正调试一套国产AI推理服务集群。没有发布会、没有PPT、没有参数对比图,只有一份干…

2026/10/14 8:50:30 阅读更多 →
Kafka IDEA实操入门:从零搭建可调试消息系统

Kafka IDEA实操入门:从零搭建可调试消息系统

1. 项目概述:为什么一个Kafka入门教程要特别强调IDEA操作? “【菜鸟教程】Kafka消息队列入门下(IDEA操作Kafka)”这个标题看似平实,但藏着三个关键信号:第一,“菜鸟教程”不是指内容浅薄&#x…

2026/10/14 8:50:30 阅读更多 →
rh2288hv2固件升级实战:BIOS与BMC刷写顺序、避坑与救砖指南

rh2288hv2固件升级实战:BIOS与BMC刷写顺序、避坑与救砖指南

简介:这份资源是华为 RH2288HV2 服务器的 BIOS 与 BMC 固件升级包,版本为 7.38,面向负责服务器运维、机房管理及硬件维护的技术人员。BIOS 负责硬件初始化与系统引导,BMC 承担远程监控与带外管理,二者同步更新可提升启…

2026/10/14 8:50:30 阅读更多 →
充电站选址优化:混合整数规划与遗传算法的工程实践

充电站选址优化:混合整数规划与遗传算法的工程实践

简介:这是一份围绕电动汽车充电站选址优化问题的学术论文,聚焦新能源汽车配套设施规划中的关键问题,适合交通规划、电气工程及新能源领域的研究人员、相关专业学生和从业者参考。文档从充电需求点分布、服务半径与最大服务数量等角度出发&…

2026/10/14 8:50:30 阅读更多 →
[玩转大模型] 第十一篇:售卖自己的 Skill——买断、订阅、定制、开源+付费增强,四条路到底哪条能收到钱

[玩转大模型] 第十一篇:售卖自己的 Skill——买断、订阅、定制、开源+付费增强,四条路到底哪条能收到钱

💡 上一篇我把自己的 Skill 仓库摊开做体检,结论挺难看:十二个 Skill,三个连 name 和目录名都对不上。但那篇文章里还藏着一个我没回答的问题——既然整理到能公开了,那能不能顺便收点钱? 我认真查过这件事…

2026/10/14 8:49:29 阅读更多 →

日新闻

AnyPS5通用适配层设计:兼容性与性能的工程取舍

AnyPS5通用适配层设计:兼容性与性能的工程取舍

1. 从"AnyPS5"这个名字说起:它到底想解决什么问题第一次看到"AnyPS5"这个标题,我脑子里冒出来的第一个念头是:这大概率是一个围绕"跨平台运行"或者"通用适配"做文章的项目。名字里的"Any"…

2026/10/14 0:00:41 阅读更多 →
Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

Flutter跨平台开发实战:二手交易应用与HarmonyOS适配

1. 项目概述:Flutter跨平台二手交易应用开发作为一名长期从事移动应用开发的工程师,我最近完成了一个基于Flutter框架的二手物品交易平台项目。这个项目最吸引我的地方在于它完美结合了Flutter的跨平台优势与HarmonyOS的生态特性,实现了"…

2026/10/14 0:00:41 阅读更多 →
DFS算法解决飞机降落调度问题实战

DFS算法解决飞机降落调度问题实战

1. 项目背景与核心思路飞机降落问题是一个经典的调度优化场景,也是算法竞赛和面试中的高频题目。这个题目要求我们合理安排多架飞机的降落顺序和时间,确保所有飞机都能安全着陆而不发生冲突。在实际航空管制中,这类问题直接关系到飞行安全和机…

2026/10/14 0:00:41 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/14 3:30:28 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/13 16:22:04 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/14 3:29:58 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 22:01:27 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/13 14:57:39 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/14 7:53:34 阅读更多 →