我正在尝试在我的fastapi后端项目中使用OAuth2。
而我
下面是我的代码片段
from fastapi import APIRouter, HTTPException, status, Depends
from fastapi.security.oauth2 import OAuth2PasswordRequestForm
from ..modules import oauth_module
from ..models.user_model import User
from ..schemas import token_schema
router = APIRouter(
    prefix="/auth",
    tags=["auth"],
)
...
@router.get("/my_info")
async def read_user_info(current_user: User = Depends(oauth_module.get_current_active_user)):
    return current_user这段代码返回python TypeError,如下所示
Process SpawnProcess-12:
Traceback (most recent call last):
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/multiprocessing/process.py", line 108, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/uvicorn/subprocess.py", line 76, in subprocess_started
    target(sockets=sockets)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/uvicorn/server.py", line 50, in run
    loop.run_until_complete(self.serve(sockets=sockets))
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/uvicorn/server.py", line 57, in serve
    config.load()
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/uvicorn/config.py", line 318, in load
    self.loaded_app = import_from_string(self.app)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/uvicorn/importer.py", line 22, in import_from_string
    module = importlib.import_module(module_str)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
  File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 855, in exec_module
  File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
  File "/Users/supergrammer/GitRepository/AI_Stock_Helper/./user_app/main.py", line 6, in <module>
    from .routers import user_router, user_auth_router
  File "/Users/supergrammer/GitRepository/AI_Stock_Helper/./user_app/routers/user_auth_router.py", line 29, in <module>
    async def read_user_info(current_user: User = Depends(oauth_module.get_current_active_user)):
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/routing.py", line 564, in decorator
    self.add_api_route(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/routing.py", line 509, in add_api_route
    route = route_class(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/routing.py", line 393, in __init__
    self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 295, in get_dependant
    sub_dependant = get_param_sub_dependant(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 117, in get_param_sub_dependant
    return get_sub_dependant(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 153, in get_sub_dependant
    sub_dependant = get_dependant(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 295, in get_dependant
    sub_dependant = get_param_sub_dependant(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 117, in get_param_sub_dependant
    return get_sub_dependant(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 153, in get_sub_dependant
    sub_dependant = get_dependant(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 302, in get_dependant
    param_field = get_param_field(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/dependencies/utils.py", line 394, in get_param_field
    field = create_response_field(
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/site-packages/fastapi/utils.py", line 65, in create_response_field
    return response_field(field_info=field_info)
  File "pydantic/fields.py", line 342, in pydantic.fields.ModelField.__init__
  File "pydantic/fields.py", line 445, in pydantic.fields.ModelField.prepare
  File "pydantic/fields.py", line 473, in pydantic.fields.ModelField._set_default_and_type
  File "pydantic/fields.py", line 345, in pydantic.fields.ModelField.get_default
  File "pydantic/utils.py", line 630, in pydantic.utils.smart_deepcopy
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 270, in _reconstruct
    state = deepcopy(state, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 230, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 270, in _reconstruct
    state = deepcopy(state, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 230, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 270, in _reconstruct
    state = deepcopy(state, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 230, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 172, in deepcopy
    y = _reconstruct(x, memo, *rv)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 270, in _reconstruct
    state = deepcopy(state, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 146, in deepcopy
    y = copier(x, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 230, in _deepcopy_dict
    y[deepcopy(key, memo)] = deepcopy(value, memo)
  File "/Users/supergrammer/anaconda3/envs/FastAPI/lib/python3.9/copy.py", line 161, in deepcopy
    rv = reductor(4)
TypeError: cannot pickle 'module' object我不知道为什么这段代码返回TypeError,我认为它可能与async/await有关。
我在下面添加了我的oauth_module代码片段...
from datetime import datetime, timedelta
from fastapi import HTTPException, status, Depends, Security
from fastapi.security.oauth2 import OAuth2PasswordBearer, OAuth2PasswordRequestForm, SecurityScopes
from passlib.context import CryptContext
from jose import JWTError, jwt
from pydantic import ValidationError
from sqlalchemy.orm import Session
from ..models.user_model import User
from ..schemas import token_schema
from ..config.config import get_configurations
from ..config.database import get_db
c = get_configurations()
SECRET_KEY = c.secret_key
HASH_ALGORITHM = c.hash_algorithm
ACCESS_TOKEN_EXPIRE_MINUTES = c.access_token_expire_minutes
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(
    tokenUrl="token",
    scopes={"userinfo": "gg"}
)
def verify_password(plain, hashed):
    return pwd_context.verify(plain, hashed)
def get_hashed_password(plain):
    return pwd_context.hash(plain)
def is_authenticated_user(form_data: OAuth2PasswordRequestForm, db: Session = get_db()):
    user = db.query(User).filter(User.email == form_data.username).first()
    if not user or \
        not verify_password(form_data.password, user.password.password_history[-1]):
        return False
    return user    
def create_access_token(data: dict, expire_minutes: int = ACCESS_TOKEN_EXPIRE_MINUTES):
    to_encode = data.copy()
    to_encode.update(
        {"exp": datetime.utcnow() + timedelta(minutes=expire_minutes)})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=HASH_ALGORITHM)
    return encoded_jwt
async def get_current_user(security_scopes: SecurityScopes, token: str = Depends(oauth2_scheme), db: Session = get_db()):
    authenticate_value = "Bearer" \
            + f' scope="{security_scopes.scope_str}"' if security_scopes.scopes else ''
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": authenticate_value}
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[HASH_ALGORITHM])
        email: str = payload.get("email")
        if not email:
            raise credentials_exception
        token_scopes = payload.get("scopes", [])
        token_data = token_schema.TokenData(email=email, scopes=token_scopes)
    except (JWTError, ValidationError):
        raise credentials_exception
    user = db.query(User).filter(User.email == email).first()
    if not user:
        raise credentials_exception
    for scope in security_scopes.scopes:
        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 get_current_active_user(current_user: User = Security(get_current_user, scopes=[])):
    if not current_user:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Inactive user")
    return current_user请帮帮我。도와주세요...
发布于 2021-06-21 00:37:24
在您发布的端点定义之上,重要的部分确实在用户模型中。
# base_model.py
from sqlalchemy import Column, DateTime
from sqlalchemy.sql import func
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class BaseMixin():
    created_date = Column(DateTime(timezone=True), default=func.now(), nullable=False)
    updated_date = Column(DateTime(timezone=True), default=func.now(), onupdate=func.now(), nullable=False)
# user.py
#... other sqlalchemy imports
from .base_model import Base, BaseMixin
class User(Base, BaseMixin):
    __tablename__ = "user"
    id = Column(UUID(as_uuid=True), primary_key=True, index=True, nullable=False, default=uuid.uuid4)
    email = Column(String(51), unique=True, index=True, nullable=False)
    password = relationship( \
        "Password",
        backref=backref("user", uselist=False),
        primaryjoin='foreign(User.id) == remote(Password.id)')
    # etc sqlalchemy fields根本的问题是,您为其定义的用户模型依赖于您的端点,因为current_user: User = Depends(oauth_module.get_current_active_user))是一个sqlalchemy模型。当然,oauth_module.get_current_active_user是一个可调用的,我假设它可以自己工作。但由于您将依赖项的类型定义为User,因此fastapi将查看该模型以生成api文档和验证。然后失败,因为它不理解sqlalchemy模型。Fastapi适用于pydantic模型。您可以在堆栈跟踪中看到对许多get_dependant (用于嵌套的Depends结构)的fastapi调用,然后是get_param_field和create_response_field,然后将其带到pydantic以尝试解析模型。
你的解决方案将是不键入你的依赖,和/或创建一个代理类。您可以在任何类的__init__中声明一个Depends(),这将是您定义此调用以从db获取用户的位置,并使用该类作为代理,您可以更安全地输入。
class ProxyUser():
    def __init__(self, user = Depends(oauth_module.get_current_active_user)):
        self.user = user
@router.get("/my_info")
async def read_user_info(current_user = Depends(ProxyUser)):
    return current_user.user在任何情况下,将用户的公共API表示与DB表示分开将是一个好主意,因此两个单独的模型在这方面也会有所帮助。
https://stackoverflow.com/questions/68053973
复制相似问题