Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
25d45de
Fixture fix.
Temmmmmo Jul 28, 2023
3cdebb4
Added userdata in user information
Temmmmmo Jul 29, 2023
f8d93bd
Added userdata in user information
Temmmmmo Jul 29, 2023
dd6d753
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
6aa18a4
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
a749c6b
Merge remote-tracking branch 'origin/fixture-fix' into fixture-fix
Temmmmmo Jul 29, 2023
8c50fed
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
3001a8b
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
a90e9e2
Revert "Added userdata in user information. Fixes after review."
Temmmmmo Jul 29, 2023
a45cf06
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
1b16e94
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
7dbbc28
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
0141133
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
51e41e7
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
fcb4129
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
b61536b
Added userdata in user information. Fixes after review.
Temmmmmo Jul 29, 2023
99f5a7d
Added userdata in user information. Fixes after review.
Temmmmmo Jul 30, 2023
0b6ce37
Added userdata in user information. Fixes after review.
Temmmmmo Jul 31, 2023
6e9526f
Added userdata in user information. Fixes after review.
Temmmmmo Jul 31, 2023
113db3d
Added userdata in user information. Fixes after review.
Temmmmmo Jul 31, 2023
e2b0527
Added userdata in user information. Fixes after review.
Temmmmmo Jul 31, 2023
54f4fc2
Added userdata in user information. Fixes after review.
Temmmmmo Jul 31, 2023
f14566a
Added userdata in user information. Fixes after review.
Temmmmmo Jul 31, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions auth_lib/aiomethods.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,25 @@

import aiohttp

from .exceptions import AuthFailed, SessionExpired
from .exceptions import AuthFailed, IncorrectData, NotFound, SessionExpired

# See docs on https://api.test.profcomff.com/?urls.primaryName=auth


class AsyncAuthLib:
url: str
auth_url: str
userdata_url: str

def __init__(self, url: str):
self.url = url
def __init__(self, *, auth_url: str | None = None, userdata_url: str | None = None):
self.auth_url = auth_url
self.userdata_url = userdata_url

async def email_login(self, email: str, password: str) -> dict[str, Any]:
json = {"email": email, "password": password}
async with aiohttp.ClientSession() as session:
response = await session.post(url=f"{self.url}/email/login", json=json)
response = await session.post(
url=urljoin(self.auth_url, "email/login"), json=json
)
match response.status:
case 200:
return await response.json()
Expand All @@ -28,7 +32,7 @@ async def check_token(self, token: str) -> dict[str, Any] | None:
headers = {"Authorization": token}
async with aiohttp.request(
"GET",
urljoin(self.url, "me"),
urljoin(self.auth_url, "me"),
headers={"Authorization": token},
params={
"info": [
Expand All @@ -45,7 +49,9 @@ async def check_token(self, token: str) -> dict[str, Any] | None:
async def logout(self, token: str) -> bool:
headers = {"Authorization": token}
async with aiohttp.ClientSession() as session:
response = await session.post(url=f"{self.url}/logout", headers=headers)
response = await session.post(
url=urljoin(self.auth_url, "logout"), headers=headers
)

match response.status:
case 200:
Expand All @@ -54,3 +60,13 @@ async def logout(self, token: str) -> bool:
raise AuthFailed(response=await response.json())
case 403:
raise SessionExpired(response=await response.json())

async def get_user_data(self, token: str, user_id: int) -> dict[str | Any] | None:
headers = {"Authorization": token}
async with aiohttp.ClientSession() as session:
response = await session.get(
url=urljoin(self.userdata_url, f"user/{user_id}"), headers=headers
)
if response.ok:
return await response.json()
return None
47 changes: 41 additions & 6 deletions auth_lib/fastapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@

class UnionAuthSettings(BaseSettings):
AUTH_URL: str = "https://api.test.profcomff.com/auth/"
USERDATA_URL: str = "https://api.test.profcomff.com/userdata/"
AUTH_AUTO_ERROR: bool = True
AUTH_ALLOW_NONE: bool = False
ENABLE_USERDATA: bool = False
model_config = ConfigDict(case_sensitive=True, env_file=".env", extra="ignore")


class UnionAuth(SecurityBase):
model = APIKey.construct(in_=APIKeyIn.header, name="Authorization")
model = APIKey.model_construct(in_=APIKeyIn.header, name="Authorization")
scheme_name = "token"
settings = UnionAuthSettings()

Expand All @@ -29,23 +31,38 @@ def __init__(
scopes: list[str] = [],
auto_error: bool | None = None,
allow_none: bool | None = None,
enable_userdata: bool | None = None,
auth_url=None, # Для обратной совместимости
userdata_url=None,
) -> None:
if auth_url is not None:
warn(
"auth_url in args deprecated, use AUTH_URL env instead",
DeprecationWarning,
)
if userdata_url is not None:
warn(
"userdata_url in args deprecated, use USERDATA_URL env instead",
DeprecationWarning,
)
super().__init__()
self.auth_url = auth_url or self.settings.AUTH_URL
if not self.auth_url.endswith("/"):
self.auth_url = self.auth_url + "/"
self.userdata_url = userdata_url or self.settings.USERDATA_URL
if not self.userdata_url.endswith("/"):
self.userdata_url = self.userdata_url + "/"
self.auto_error = (
auto_error if auto_error is not None else self.settings.AUTH_AUTO_ERROR
)
self.allow_none = (
allow_none if allow_none is not None else self.settings.AUTH_ALLOW_NONE
)
self.enable_userdata = (
enable_userdata
if enable_userdata is not None
else self.settings.ENABLE_USERDATA
)
self.scopes = scopes

def _except(self):
Expand All @@ -61,20 +78,38 @@ async def _get_session(self, token: str | None) -> dict[str, Any] | None:
return None
if not token:
return self._except()
return await AsyncAuthLib(url=self.auth_url).check_token(token)
return await AsyncAuthLib(auth_url=self.auth_url).check_token(token)

async def _get_userdata(
self, token: str | None, user_id: int
) -> dict[str, Any] | None:
if not token and self.allow_none:
return None
if not token:
return self._except()
if self.enable_userdata:
return await AsyncAuthLib(userdata_url=self.userdata_url).get_user_data(
token, user_id
)
return None
Comment thread
grigoriev-semyon marked this conversation as resolved.

async def __call__(
self,
request: Request,
) -> dict[str, Any] | None:
token = request.headers.get("Authorization")
user_session = await self._get_session(token)
if user_session is None:
result = await self._get_session(token)
if result is None:
return self._except()
if self.enable_userdata:
user_data_info = await self._get_userdata(token, result["id"])
result["userdata"] = []
if user_data_info is not None:
result["userdata"] = user_data_info["items"]
session_scopes = set(
[scope["name"].lower() for scope in user_session["session_scopes"]]
[scope["name"].lower() for scope in result["session_scopes"]]
)
required_scopes = set([scope.lower() for scope in self.scopes])
if required_scopes - session_scopes:
self._except()
return user_session
return result
26 changes: 18 additions & 8 deletions auth_lib/methods.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,22 @@

import requests

from .exceptions import AuthFailed, SessionExpired
from .exceptions import AuthFailed, IncorrectData, NotFound, SessionExpired

# See docs on https://api.test.profcomff.com/?urls.primaryName=auth


class AuthLib:
url: str
auth_url: str
userdata_url: str

def __init__(self, url: str):
self.url = url
def __init__(self, *, auth_url: str | None = None, userdata_url: str | None = None):
self.auth_url = auth_url
self.userdata_url = userdata_url

def email_login(self, email: str, password: str) -> dict[str, Any]:
json = {"email": email, "password": password}
response = requests.post(url=f"{self.url}/email/login", json=json)
response = requests.post(url=urljoin(self.auth_url, "email/login"), json=json)
match response.status_code:
case 200:
return response.json()
Expand All @@ -26,7 +28,7 @@ def email_login(self, email: str, password: str) -> dict[str, Any]:
def check_token(self, token: str) -> dict[str, Any] | None:
headers = {"Authorization": token}
response = requests.get(
url=urljoin(self.url, "me"),
url=urljoin(self.auth_url, "me"),
headers=headers,
params={
"info": [
Expand All @@ -41,12 +43,20 @@ def check_token(self, token: str) -> dict[str, Any] | None:

def logout(self, token: str) -> bool:
headers = {"Authorization": token}
response = requests.post(url=f"{self.url}/logout", headers=headers)

response = requests.post(url=urljoin(self.auth_url, "logout"), headers=headers)
match response.status_code:
case 200:
return True
case 401:
raise AuthFailed(response=response.json()["body"])
case 403:
raise SessionExpired(response=response.json()["body"])

def get_user_data(self, token: str, user_id: int) -> dict[str | Any] | None:
headers = {"Authorization": token}
response = requests.get(
url=urljoin(self.userdata_url, f"user/{user_id}"), headers=headers
)
if response.ok:
return response.json()
return None
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from setuptools import find_packages, setup

with open("README.md", "r") as readme_file:
with open("README.md", "r", encoding="utf-8") as readme_file:
readme = readme_file.read()

setup(
Expand Down