Как добавить Oauth2 авторизацию к JWT?

Пытаюсь сделать авторизацию с помощью Oauth2 и JWT вместе с FastAPI. Получилось пока сделать так, чтобы при регистрации создавался пользователь и его учетная запись с почтой и паролем и возвращался JWT токен с id пользователя. И чтобы при входе возвращался пользователь.

class Identity(SQLModel):
    name: str
    username: str
    mail: str
    password: str


identity_router = APIRouter(prefix="/identity", tags=["Identity"])


@identity_router.post("/signin")
async def signin(response: Response, identity: Identity):
    user_identity, token = await identity_service.signin(identity)
    if user_identity is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
        )
    response.set_cookie(
        key="session_token", value=token, httponly=True, samesite='lax',
        expires=datetime.now(timezone.utc) + timedelta(days=JWT_TOKEN_EXPIRE_DAYS)
    )
    return user_identity


@identity_router.post("/signup")
async def signup(response: Response, identity: Identity):
    user_identity, token = await identity_service.signup(identity)
    if user_identity is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User already registered",
        )
    response.set_cookie(
        key="session_token", value=token, httponly=True, samesite='lax',
        expires=datetime.now(timezone.utc) + timedelta(days=JWT_TOKEN_EXPIRE_DAYS)
    )
    return user_identity

Сейчас пытаюсь добавить получение текущего пользователя, но не совсем понимаю как это сделать. В документации говорят, что нужно использовать oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") и импротировать его в функцию get_current_user(...) Depends(oauth2_scheme). Но что дает oauth2_scheme? В чем отличие oauth2_scheme от моей модели Identity, если мне не нужно использовать скоупы Oauth2?


Ответы (1 шт):

Автор решения: sln

Разобрался как работает Oauth2 авторизация. В документации всё правильно говорят.

Я думал как сделать так, чтобы токен возвращался при регистрации, но оказывается, при регистрации не нужно возвращать токен. Нужно только создавать пользователя в базе. Токен нужно возвращать только при логине в виде {"access_token": token, "token_type": "bearer"}, либо в виде Pydentic модельки с такими же полями.

Сам ентрипоинт с логином должен принимать form_data: OAuth2PasswordRequestForm = Depends(), чтобы потом из него достать пароль password и второе значение с почтой, логином или чем угодно еще username. Можно и принимать свою модель, но тогда уже не будет работать встроенная Oauth2 авторизация, потому что своя модель уже не будет соответствовать стандарту. И в oauth2_scheme = OAuth2PasswordBearer(tokenUrl=...) уже нужно передать путь к логину.

То есть процесс выдачи доступа будет выглядеть так:

  1. Пользователь регистрируется и сохраняется в базу
  2. Пользователь логинится и получает токен
  3. Этот токен передает в заголовке запроса на защищенный энтрипоинт
  4. def get_current_user(token: str = Depends(oauth2_scheme)): ... сам достанет токен из заголовка запроса и его останется только расшифровать

То есть JWT используется только для того, чтобы валидировать токен на бэкенде.

→ Ссылка