day(04)登录认证、JWT Token 头像上传
2026/7/23 2:49:24 网站建设 项目流程

在求职平台项目中,用户认证与文件上传是核心基础功能。今天我们将实现了机号密码登录、短信验证码登录、JWT Token 生成与解析,以及头像上传到阿里云 OSS 的功能


二、核心模块与技术选型

  • 认证方式:密码登录 + 短信验证码登录
  • Token 管理:JWT(access_token + refresh_token)
  • 验证码存储:Redis(设置过期时间,防止重复获取)
  • 文件存储:阿里云 OSS(存储用户头像)
  • 框架分层:接口层(路由)+ 服务层(业务逻辑)+ 模型层(数据库)

三、数据库模型设计

首先定义求职者Jobseeker模型,存储用户核心信息:

python

运行

# app/models/jobseeker.py from tortoise import models, fields class Jobseeker(models.Model): id = fields.IntField(pk=True) phone = fields.CharField(max_length=12, description="手机号", unique=True) password = fields.CharField(max_length=12, description="密码") nickname = fields.CharField(max_length=12, description="昵称", default="用户1") avatar = fields.CharField(max_length=255, description="头像", default="无") wxchat = fields.CharField(max_length=255, description="微信号", null=True) email = fields.CharField(max_length=255, description="邮箱", null=True) create_time = fields.DatetimeField(auto_now_add=True) update_time = fields.DatetimeField(auto_now=True) class Meta: table = "jobseeker"

四、接口层实现(路由)

我们使用APIRouter模块化管理求职者接口,将路由前缀设为/jobseeker

1. 路由初始化

python

运行

# app/api/jobseeker.py from fastapi import APIRouter, Depends, UploadFile, Request from app.schemas.jobseeker import JobseekerLoginPsd, JobseekerLoginSms from app.services.jobseeker_service import JobSeekerService from app.core.depends import getinfo_form_token jobseeker_router = APIRouter(prefix="/jobseeker", tags=["求职者模块"])

2. 登录相关接口

(1)手机号 + 密码登录

python

运行

@jobseeker_router.post(path="/loginbypsd/", summary="手机号,密码登录") async def loginbypsd(logininfo: JobseekerLoginPsd): res = await JobSeekerService.loginbypsd(logininfo) return {"code": 200, "msg": "登录成功", "data": res}
(2)发送短信验证码

python

运行

@jobseeker_router.get(path='/getsms/', summary="给指定手机号发送验证码") async def getsms(phone: str): res = await JobSeekerService.getsms(phone) return {"code": 200, "msg": "发送成功"}
(3)手机号 + 验证码登录

python

运行

@jobseeker_router.post(path='/loginbysms/', summary="手机号+验证码登录") async def loginbysms(logininfo: JobseekerLoginSms): res = await JobSeekerService.loginbysms(logininfo) return {"code": 200, "msg": "登录成功", "data": res}

3. 登录后操作接口

(1)获取个人信息

通过Depends(getinfo_form_token)从 Token 中解析出用户 ID:

python

运行

@jobseeker_router.get(path='/getmyinfo/', summary='获取个人信息') async def getmyinfo(seekerid=Depends(getinfo_form_token)): res = await JobSeekerService.getmyinfo(seekerid) return {"code": 200, "msg": "获取成功", "data": res}
(2)忘记密码(重置密码)

python

运行

@jobseeker_router.put(path='/getnewpsd/', summary='忘记密码') async def getnewpsd(request: Request, seekerid=Depends(getinfo_form_token)): newpsd = await request.json() res = await JobSeekerService.getnewpsd(newpsd.get("password"), seekerid) return {"code": 200, "msg": "修改成功"}
(3)头像上传

接收UploadFile类型文件,上传到阿里云 OSS:

python

运行

@jobseeker_router.post(path='/uploadavatar/', summary='上传头像') async def uploadavatar(file: UploadFile, seekerid=Depends(getinfo_form_token)): res = await JobSeekerService.uploadavatar(file, seekerid) return {"code": 200, "msg": "上传成功"}

五、服务层实现(业务逻辑)

1. Redis 连接初始化

python

运行

import redis r = redis.Redis(host="127.0.0.1", port=6379, db=10, decode_responses=True, protocol=2)

2. 核心服务类JobSeekerService

(1)手机号 + 密码登录

python

运行

from app.models import Jobseeker from app.utils.jwt_util import create_tokens class JobSeekerService: @staticmethod async def loginbypsd(logininfo: JobseekerLoginPsd): seekerobj = await Jobseeker.get_or_none(phone=logininfo.phone) if seekerobj is None: raise Exception("手机号不存在") if seekerobj.password != logininfo.password: raise Exception("密码错误") # 生成 JWT Token access_token, refresh_token = create_tokens(seekerobj.id, seekerobj.phone) return { "access_token": access_token, "refresh_token": refresh_token, "jobseeker": seekerobj }
(2)发送短信验证码

python

运行

import re from app.utils.sms_util import get_sms_code, send_sms_code from app.core.logging import logger @staticmethod async def getsms(phone: str): if not phone: raise Exception("手机号不能为空") if not re.match(r"^1[3-9]\d{9}$", phone): raise Exception("手机号格式不对") smskey = f"sms_code:{phone}" # 防止重复获取验证码 code_redis = r.get(smskey) if code_redis: raise Exception("请勿重复获取验证码") # 生成 6 位验证码 code = str(get_sms_code(6)) # 调用第三方短信平台发送(模拟) send_sms_code(phone, code) logger.info(f"手机号为: {phone},验证码为: {code}") # 存入 Redis,2 分钟过期 r.set(smskey, code, ex=60*2) return True
(3)手机号 + 验证码登录

python

运行

@staticmethod async def loginbysms(logininfo: JobseekerLoginSms): seekerobj = await Jobseeker.get_or_none(phone=logininfo.phone) if seekerobj is None: raise Exception("用户不存在") smskey = f"sms_code:{logininfo.phone}" code_redis = r.get(smskey) if code_redis is None: raise Exception("验证码已过期,请重新获取") if code_redis != logininfo.code: raise Exception("验证码错误") # 生成 Token access_token, refresh_token = create_tokens(seekerobj.id, seekerobj.phone) # 登录成功后删除验证码 r.delete(smskey) return { "access_token": access_token, "refresh_token": refresh_token, "jobseeker": seekerobj }
(4)获取用户信息

python

运行

@staticmethod async def getmyinfo(seekerid: str): seekerobj = await Jobseeker.get_or_none(id=seekerid) if not seekerobj: raise Exception("用户不存在") return seekerobj
(5)重置密码

python

运行

@staticmethod async def getnewpsd(password: str, seekerid: str) -> bool: seekerobj = await Jobseeker.get_or_none(id=seekerid) if not seekerobj: raise Exception("用户不存在") seekerobj.password = password await seekerobj.save() return True
(6)头像上传到阿里云 OSS

python

运行

from fastapi import UploadFile from app.utils.alioss_util import AliyunOSSTool @staticmethod async def uploadavatar(file: UploadFile, seekerid: str): if not file: raise Exception("文件不能为空") # 读取文件内容 filedata = await file.read() filename = file.filename # 上传到阿里云 OSS alioss = AliyunOSSTool() issuccess, result = alioss.upload_single_file( filedata, filename, oss_path='p4boss/seeker_avatar/' ) if issuccess: seekerobj = await Jobseeker.get_or_none(id=seekerid) if not seekerobj: raise Exception("用户不存在") # 更新数据库头像地址 seekerobj.avatar = result['access_url'] await seekerobj.save() return True else: raise Exception("上传失败")

六、关键技术点解析

1. JWT Token 生成与解析

  • 生成:登录成功后,调用create_tokens()生成access_token(短有效期)和refresh_token(长有效期)。
  • 解析:通过Depends(getinfo_form_token)中间件,从请求头的Authorization中提取 Token,解析出用户 ID,实现接口鉴权。

2. Redis 缓存验证码

  • 防重发:获取验证码前先查询 Redis,若存在则拒绝重复请求。
  • 过期控制:验证码存入 Redis 时设置ex=120(2 分钟过期),确保安全性。
  • 登录后销毁:验证码登录成功后立即删除 Redis 中的验证码,防止复用。

3. 文件上传到阿里云 OSS

  • UploadFile:FastAPI 提供的文件上传类型,可直接读取文件内容和文件名。
  • OSS 工具类:封装AliyunOSSTool,实现文件上传、获取访问 URL 等功能。
  • 数据库更新:上传成功后,将 OSS 返回的access_url更新到用户avatar字段

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

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

立即咨询