FastAPI 学习之路(五十六)将token存放在redis
在之前的文章中,FastAPI 学习之路(二十九)使用(哈希)密码和 JWT Bearer 令牌的 OAuth2,FastAPI 学习之路(二十八)使用密码和 Bearer 的简单 OAuth2,FastAPI 学习之路(三十四)数据库多表操作,我们分享了基于jwt认证token和基于数据库创建用户,那么我们今天把这些代码整理下,形成基于数据库用户名密码,登陆验证token存储到redis中。
首先我们看下之前基于jwt认证token的代码
- from fastapi import Depends,status,HTTPException
- from pydantic import BaseModel
- from typing import Optional
- from jose import JWTError, jwt
- from datetime import datetime, timedelta
- from passlib.context import CryptContext
- SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
- ALGORITHM = "HS256"
- ACCESS_TOKEN_EXPIRE_MINUTES = 30
- # oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
- fake_users = {
- "leizi": {
- "username": "leizi",
- "full_name": "leizishuoceshikaifa",
- "email": "leizi@leizi.com",
- "hashed_password": "$2b$12$4grMcfV9UMijFC0CEeJOTuTHE21msQOmkUWuowUewRSXt8cimW/76",
- "disabled": False
- }
- }
- def fake_hash_password(password: str):
- return password
- class Token(BaseModel):
- access_token: str
- token_type: str
- class TokenData(BaseModel):
- username: Optional[str] = None
- password:Optional[str]=None
- class User(BaseModel):
- username: str
- email: Optional[str] = None
- full_name: Optional[str] = None
- disabled: Optional[bool] = None
- class UserInDB(User):
- hashed_password: str
- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
- def verify_password(plain_password, hashed_password):
- return pwd_context.verify(plain_password, hashed_password)
- def get_password_hash(password):
- return pwd_context.hash(password)
- def authenticate_user(fake_db, username: str, password: str):
- user = get_user(fake_db, username)
- print(get_password_hash(password))
- 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):
- 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
- def get_user(db, username: str):
- if username in db:
- user_dict = db[username]
- return UserInDB(**user_dict)
- def fake_decode_token(token):
- user = get_user(fake_users, token)
- return user
- def get_current_user(token: str = Depends()):
- credentials_exception = HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="验证失败",
- headers={"WWW-Authenticate": "Bearer"},
- )
- try:
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
- username: str = payload.get("sub")
- if username is None:
- raise credentials_exception
- token_data = TokenData(username=username)
- except JWTError:
- raise credentials_exception
- user = get_user(fake_users, username=token_data.username)
- if user is None:
- raise credentials_exception
- return user
- def get_current_active_user(current_user: User = Depends(get_current_user)):
- if current_user.disabled:
- raise HTTPException(status_code=400, detail="已经删除")
- return current_user
- @app.post("/login", response_model=Token)
- async def login_for_access_token( tokendata:TokenData):
- user = authenticate_user(fake_users,tokendata.username,tokendata.password)
- if not user:
- raise HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="Incorrect username or password",
- headers={"WWW-Authenticate": "Bearer"},
- )
- access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
- access_token = create_access_token(
- data={"sub": user.username}, expires_delta=access_token_expires
- )
- return {"access_token": access_token, "token_type": "bearer"}
我们需要把这部分代码进行调整,我们调整到routers中的user.py。其实就是把之前的方法去柔和到新的方法中,需要调整下之前的用户创建,把登陆给实现了。
我们看下新修改后的代码。
- from fastapi import APIRouter,status
- from fastapi import Depends,HTTPException
- from models.crud import *
- from get_db import get_db
- from datetime import timedelta,datetime
- from jose import JWTError, jwt
- usersRouter=APIRouter()
- SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7"
- ALGORITHM = "HS256"
- ACCESS_TOKEN_EXPIRE_MINUTES = 30
- from passlib.context import CryptContext
- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
- def verify_password(plain_password, hashed_password):
- return pwd_context.verify(plain_password, hashed_password)
- def get_password_hash(password):
- return pwd_context.hash(password)
- # 新建用户
- @usersRouter.post("/users/", tags=["users"], response_model=Users)
- def create_user(user: UserCreate, db: Session = Depends(get_db)):
- """
- - **email**: 用户的邮箱
- - **password**: 用户密码
- """
- db_crest = get_user_emai(db, user.email)
- user.password=get_password_hash(user.password)
- if not db_crest:
- return db_create_user(db=db, user=user)
- raise HTTPException(status_code=200, detail="账号不能重复")
- def create_access_token(data: dict):
- to_encode = data.copy()
- encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
- return encoded_jwt
- def get_cure(token):
- credentials_exception = HTTPException(
- status_code=status.HTTP_401_UNAUTHORIZED,
- detail="验证失败",
- headers={"WWW-Authenticate": "Bearer"},
- )
- try:
- payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
- username: str = payload.get("sub")
- if username is None:
- raise credentials_exception
- return username
- except JWTError:
- raise credentials_exception
- @usersRouter.post("/login",response_model=UsersToken)
- def login(user:UserCreate,db: Session = Depends(get_db)):
- db_crest = get_user_emai(db, user.email)
- if not db_crest:
- raise HTTPException(status_code=200, detail="账号不存在")
- pass
现在登陆还未完全实现,我们去实现下这块。
这里的UsersToken在schemas中实现。
- class UsersToken(UserBase):
- token: str
登陆的实现我们实现如下
- @usersRouter.post("/login",response_model=UsersToken)
- async def login(request: Request,user:UserCreate,db: Session = Depends(get_db)):
- #查看用户是否存在
- db_crest = get_user_emai(db, user.email)
- if not db_crest:
- raise HTTPException(status_code=200, detail="账号不存在")
- #校验密码
- verifypassowrd=verify_password(user.password,db_crest.password)
- if verifypassowrd:
- #产生token
- token=create_access_token(data={"sub": user.email})
- useris=await request.app.state.redis.get(user.email)
- if not useris:
- request.app.state.redis.set(user.email,token,expire=ACCESS_TOKEN_EXPIRE_MINUTES*60)
- usertoken=UsersToken(token=token,email=user.email)
- return usertoken
- raise HTTPException(status_code=200, detail="请勿重复登陆")
- else:
- raise HTTPException(status_code=200, detail="密码错误")
redis相关的还是在我们上次分享的时候的FastAPI 学习之路(五十四)操作Redis。
我们去启动下去测试下,看我们实现的是否正确。
由于我们更新了我们的创建用户的时候的密码的hash呢,我们先去创建用户
接下来,我们调用我们的登录
发现登陆报错了。
这里我们在设计数据库的时候用的是hashed_password存储的密码,我们这里需要修改下
- verifypassowrd=verify_password(user.password,db_crest.hashed_password)
然后我们在测试下
这样我们的token就产生了,我们也在redis有了存储
那么接下来会分享如何校验token?
通过本次的分享,我们讲登陆的用户存储到了数据库中,讲登陆后的产生的token我们存储到了redis上了。这样我们的存储持久化,接下来,我会分享如何校验token做判断是否登陆。
所有的代码,都会放在gitee上,大家可以后续看到完整的代码。后续将开发几个接口,和结合我们的接口测试来分享。欢迎持续关注。
- https://gitee.com/liwanlei/fastapistuday
文章首发在公众号,欢迎关注。
FastAPI 学习之路(五十六)将token存放在redis的更多相关文章
- FastAPI 学习之路(十六)Form表单
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- FastAPI 学习之路(十八)表单与文件
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- FastAPI 学习之路(十九)处理错误
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- FastAPI 学习之路(十五)响应状态码
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- FastAPI 学习之路(十二)接口几个额外信息和额外数据类型
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- FastAPI 学习之路(十四)响应模型
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- FastAPI 学习之路(十)请求体的字段
系列文章: FastAPI 学习之路(一)fastapi--高性能web开发框架 FastAPI 学习之路(二) FastAPI 学习之路(三) FastAPI 学习之路(四) FastAPI 学习之 ...
- Kubernetes学习之路(十六)之存储卷
目录 一.存储卷的概念和类型 二.emptyDir存储卷演示 三.hostPath存储卷演示 四.nfs共享存储卷演示 五.PVC和PV的概念 六.NFS使用PV和PVC 1.配置nfs存储 2.定义 ...
- Vue学习之路第十六篇:车型列表的添加、删除与检索项目
又到了大家最喜欢的项目练习阶段,学以致用,今天我们要用前几篇的学习内容实现列表的添加与删除. 学前准备: ①:JavaScript中的splice(index,i)方法:从已知数组的index下标开始 ...
随机推荐
- SVN无法查看最近日志和提交记录
现象: 使用SVN查看最近的提交记录日志时,最近总是无法显示出全部的日志内容,只能显示到几天之前的日志.就算是自己刚提交的代码也是无法没有记录的. 解决方式:右键选择TortoiseSVN中的&quo ...
- 关于JDK高版本下RMI、LDAP+JNDI bypass的一点笔记
1.关于RMI 只启用RMI服务时,这时候RMI客户端能够去打服务端,有两种情况,第一种就是利用服务端本地的gadget,具体要看服务端pom.xml文件 比如yso中yso工具中已经集合了很多gad ...
- wpf内存泄漏问题
http://www.cnblogs.com/Cindys/archive/2012/05/17/2505893.html http://blogs.msdn.com/b/jgoldb/archive ...
- CodeForce-811C Vladik and Memorable Trip(动态规划)
Vladik and Memorable Trip CodeForces - 811C 有一个长度为 n 的数列,其中第 i 项为 ai. 现在需要你从这个数列中选出一些互不相交的区间,并且保证整个数 ...
- 【简单数据结构】链表--洛谷P1160
题目描述 一个学校里老师要将班上NN个同学排成一列,同学被编号为1\sim N1∼N,他采取如下的方法: 先将11号同学安排进队列,这时队列中只有他一个人: 2-N2−N号同学依次入列,编号为i的同学 ...
- PHP中操作任意精度大小的GMP扩展学习
对于各类开发语言来说,整数都有一个最大的位数,如果超过位数就无法显示或者操作了.其实,这也是一种精度越界之后产生的精度丢失问题.在我们的 PHP 代码中,最大的整数非常大,我们可以通过 PHP_INT ...
- windows 中cmd一些特殊命令
chcp 65001 就是换成UTF-8代码页 chcp 936 可以换回默认的GBK chcp 437 是美国英语 shutdown -s -t 60 60秒后关机 shutdown /a ...
- Kotlin协程基础
开发环境 IntelliJ IDEA 2021.2.2 (Community Edition) Kotlin: 212-1.5.10-release-IJ5284.40 我们已经通过第一个例子学会了启 ...
- javascript 编码规范 - 正确使用parseInt
题目描述 修改 js 代码中 parseInt 的调用方式,使之通过全部测试用例 示例1 输入 '12' 输出 12 示例2 输入 复制 '12px' 输出 复制 12 示例3 输入 '0x12' 输 ...
- python学习笔记(五)-文件操作2
一.文件修改 现有文件file.txt,内容如下:二十四节气歌春雨惊春清谷天,夏满芒夏暑相连.秋处露秋寒霜降,冬雪雪冬小大寒.上半年逢六廿一,下半年逢八廿三.每月两节日期定,最多相差一二天.要求:将文 ...