1.JWT认证
from datetime import datetime, timedelta
from passlib.context import CryptContext
from jose import JWTError, jwt
SECRET_KEY = "60a633523fb43587dc02f6bd0f22a73a1d5d0b69f9de489de39523da92a7d2da"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
class Token(BaseModel):
access_token: str
token_type: str
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
jwt_schema = OAuth2PasswordBearer(tokenUrl="/jwt") # 认证接口地址
def verify_password(plain_password, hashed_password):
"""对密码进行校验"""
return pwd_context.verify(plain_password, hashed_password)
def jwt_get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def jwt_authenticate_user(db, username: str, password: str):
user = jwt_get_user(db, username)
if not user:
return False
if not verify_password(password, user.hashed_password):
return False
return user
def create_access_token(data: dict, expire_delta: Optional[timedelta] = None):
"""创建Token"""
to_encode = data.copy()
if expire_delta:
expire = datetime.utcnow() + expire_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encode_jwt = jwt.encode(claims=to_encode, key=SECRET_KEY, algorithm=ALGORITHM)
return encode_jwt
@tokens.post("/jwt", response_model=Token, summary="JWT获取token")
async def login_jwt(form_data: OAuth2PasswordRequestForm = Depends()):
user = jwt_authenticate_user(db=fake_users_db, username=form_data.username, password=form_data.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)
assess_token = create_access_token(data={"sub": form_data.username}, expire_delta=access_token_expires)
return {"access_token": assess_token, "token_type": "Bearer"}
def jwt_get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
async def jwt_get_current_user(token: str = Depends(jwt_schema)):
"""获取当前用户"""
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Can not validate credentials",
headers={"WWW-Authenticate": "Bearer"}
)
try:
# 校验Token合法性,内部会校验过期时间
payload = jwt.decode(token=token, key=SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
if not username:
raise credentials_exception
except JWTError:
raise credentials_exception
user = jwt_get_user(db=fake_users_db, username=username)
if not user:
raise credentials_exception
return user
async def jwt_get_current_activate_user(current_user: User = Depends(jwt_get_current_user)):
"""获取当前活跃的用户"""
if current_user.disabled:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Inactive user"
)
return current_user
@tokens.get("/jwt_current_user", summary="获取活跃用户")
async def jwt_read_user_info(current_user: User = Depends(jwt_get_current_activate_user)):
"""获取活跃的用户"""
return current_user
2.JWT加权限认证
from typing import Optional, List
from datetime import datetime, timedelta
from dynaconf import ValidationError
from fastapi import APIRouter, Depends, HTTPException, Security
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm, SecurityScopes
from pydantic import BaseModel
from starlette import status
from passlib.context import CryptContext
from jose import JWTError, jwt
tokens = APIRouter()
# 模拟数据库数据
fake_users_db = {
"jack": {
"username": "jack",
"full_name": "Jack",
"email": "jack@qq.com",
"hashed_password": "d2h3k2n4h23bn4b23h53mbn3bm24mmn43",
"disabled": True
},
"lucy": {
"username": "lucy",
"full_name": "Lucy",
"email": "lucy@qq.com",
"hashed_password": "9d34lk2n6h23le4b23h53mbn3bm24mg2nhk",
"disabled": False
}
}
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
class UserInDB(User):
hashed_password: str
SECRET_KEY = "60a633523fb43587dc02f6bd0f22a73a1d5d0b69f9de489de39523da92a7d2da"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Optional[str] = None
scopes: List[str] = []
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
jwt_schema = OAuth2PasswordBearer(
tokenUrl="/token/jwt",
scopes={
"get_admin_info": "获取管理员用户信息",
"del_admin_info": "删除管理员用户信息",
"get_user_info": "获取用户信息",
"get_user_role": "获取用户所属角色信息",
"get_user_permission": "获取用户相关的权限信息",
})
def verify_password(plain_password, hashed_password):
"""对密码进行校验"""
# 为了方便,这里就不对密码进行校验了!直接通过!!!只是为了方便!
# 加密:encryption_pwd.hash(pwd)
# return pwd_context.verify(plain_password, hashed_password)
return True
def jwt_get_user(db, username: str):
if username in db:
user_dict = db[username]
return UserInDB(**user_dict)
def jwt_authenticate_user(db, username: str, password: str):
user = jwt_get_user(db, username)
if not user:
return False
if not verify_password(password, user.hashed_password):
return False
return user
def create_access_token(data: dict, expire_delta: Optional[timedelta] = None):
to_encode = data.copy()
if expire_delta:
expire = datetime.utcnow() + expire_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encode_jwt = jwt.encode(claims=to_encode, key=SECRET_KEY, algorithm=ALGORITHM)
return encode_jwt
@tokens.post("/jwt", response_model=Token, summary="获取token")
async def login_jwt(form_data: OAuth2PasswordRequestForm = Depends()):
user = jwt_authenticate_user(db=fake_users_db, username=form_data.username, password=form_data.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)
assess_token = create_access_token(data={"sub": form_data.username, "scopes": form_data.scopes},
expire_delta=access_token_expires)
return {"access_token": assess_token, "token_type": "Bearer"}
async def jwt_get_current_user(security_scopes: SecurityScopes, token: str = Depends(jwt_schema)):
"""获取当前用户"""
print("当前认证方案里面的作用域:", security_scopes.scope_str)
if security_scopes.scopes:
authenticate_value = f'Bearer scope="{security_scopes.scope_str}"'
else:
authenticate_value = f"Bearer"
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Can not validate credentials",
headers={"WWW-Authenticate": "Bearer"}
)
try:
# 内部会校验过期时间
payload = jwt.decode(token=token, key=SECRET_KEY, algorithms=[ALGORITHM])
username = payload.get("sub")
if not username:
raise credentials_exception
token_scopes = payload.get("scopes", [])
print("当前用户所属的token信息里面包含的scopes信息有:", token_scopes)
token_data = TokenData(scopes=token_scopes, username=username)
print("token_data", token_data)
except (JWTError, ValidationError):
raise credentials_exception
user = jwt_get_user(db=fake_users_db, username=username)
if not user:
raise credentials_exception
print("当前认证方案里面所有security_scopes信息有:", security_scopes.scopes)
for scope in security_scopes.scopes:
# 对比用户的token锁携带的用户的作用区域授权信息
if scope not in token_data.scopes:
# 如果不存在则返回没有权限异常信息
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not enough permissions",
headers={"WWW-Authenticate": authenticate_value},
)
return user
async def jwt_get_current_activate_user(current_user: User = Depends(jwt_get_current_user)):
"""获取当前活跃的用户"""
if current_user.disabled:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Inactive user"
)
return current_user
@tokens.get("/jwt_current_user_info", response_model=User, summary="获取用户信息")
async def get_admin_info(current_user: User = Security(jwt_get_current_activate_user, scopes=["get_user_info"])):
"""获取活跃的用户"""
return current_user