refresh-token
This commit is contained in:
@@ -2,48 +2,14 @@ from functools import wraps
|
||||
from typing import Optional, Tuple
|
||||
|
||||
from graphql.type import GraphQLResolveInfo
|
||||
from jwt import DecodeError, ExpiredSignatureError
|
||||
from starlette.authentication import AuthenticationBackend
|
||||
from starlette.requests import HTTPConnection
|
||||
|
||||
from auth.credentials import AuthCredentials, AuthUser
|
||||
from auth.jwtcodec import JWTCodec
|
||||
from auth.tokenstorage import TokenStorage
|
||||
from base.exceptions import ExpiredToken, InvalidToken
|
||||
from services.auth.users import UserStorage
|
||||
from settings import SESSION_TOKEN_HEADER
|
||||
|
||||
|
||||
class SessionToken:
|
||||
@classmethod
|
||||
async def verify(cls, token: str):
|
||||
"""
|
||||
Rules for a token to be valid.
|
||||
1. token format is legal &&
|
||||
token exists in redis database &&
|
||||
token is not expired
|
||||
2. token format is legal &&
|
||||
token exists in redis database &&
|
||||
token is expired &&
|
||||
token is of specified type
|
||||
"""
|
||||
try:
|
||||
print('[auth.authenticate] session token verify')
|
||||
payload = JWTCodec.decode(token)
|
||||
except ExpiredSignatureError:
|
||||
payload = JWTCodec.decode(token, verify_exp=False)
|
||||
if not await cls.get(payload.user_id, token):
|
||||
raise ExpiredToken("Token signature has expired, please try again")
|
||||
except DecodeError as e:
|
||||
raise InvalidToken("token format error") from e
|
||||
else:
|
||||
if not await cls.get(payload.user_id, token):
|
||||
raise ExpiredToken("Session token has expired, please login again")
|
||||
return payload
|
||||
|
||||
@classmethod
|
||||
async def get(cls, uid, token):
|
||||
return await TokenStorage.get(f"{uid}-{token}")
|
||||
from auth.tokenstorage import SessionToken
|
||||
from base.exceptions import InvalidToken
|
||||
|
||||
|
||||
class JWTAuthenticate(AuthenticationBackend):
|
||||
@@ -54,10 +20,18 @@ class JWTAuthenticate(AuthenticationBackend):
|
||||
if SESSION_TOKEN_HEADER not in request.headers:
|
||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||
|
||||
token = request.headers.get(SESSION_TOKEN_HEADER, "")
|
||||
token = request.headers.get(SESSION_TOKEN_HEADER)
|
||||
if not token:
|
||||
print("[auth.authenticate] no token in header %s" % SESSION_TOKEN_HEADER)
|
||||
return AuthCredentials(scopes=[], error_message=str("no token")), AuthUser(
|
||||
user_id=None
|
||||
)
|
||||
|
||||
try:
|
||||
payload = await SessionToken.verify(token)
|
||||
if len(token.split('.')) > 1:
|
||||
payload = await SessionToken.verify(token)
|
||||
else:
|
||||
InvalidToken("please try again")
|
||||
except Exception as exc:
|
||||
print("[auth.authenticate] session token verify error")
|
||||
print(exc)
|
||||
|
@@ -20,7 +20,7 @@ class AuthCredentials(BaseModel):
|
||||
return True
|
||||
|
||||
async def permissions(self) -> List[Permission]:
|
||||
if self.user_id is not None:
|
||||
if self.user_id is None:
|
||||
raise OperationNotAllowed("Please login first")
|
||||
return NotImplemented()
|
||||
|
||||
|
@@ -8,12 +8,11 @@ from settings import JWT_ALGORITHM, JWT_SECRET_KEY
|
||||
class JWTCodec:
|
||||
@staticmethod
|
||||
def encode(user: AuthInput, exp: datetime) -> str:
|
||||
issued = datetime.now(tz=timezone.utc)
|
||||
payload = {
|
||||
"user_id": user.id,
|
||||
"username": user.email or user.phone,
|
||||
"exp": exp,
|
||||
"iat": issued,
|
||||
"iat": datetime.now(tz=timezone.utc),
|
||||
"iss": "discours"
|
||||
}
|
||||
try:
|
||||
|
@@ -13,9 +13,30 @@ async def save(token_key, life_span, auto_delete=True):
|
||||
await redis.execute("EXPIREAT", token_key, int(expire_at))
|
||||
|
||||
|
||||
class SessionToken:
|
||||
@classmethod
|
||||
async def verify(cls, token: str):
|
||||
"""
|
||||
Rules for a token to be valid.
|
||||
- token format is legal
|
||||
- token exists in redis database
|
||||
- token is not expired
|
||||
"""
|
||||
try:
|
||||
return JWTCodec.decode(token)
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
@classmethod
|
||||
async def get(cls, uid, token):
|
||||
return await TokenStorage.get(f"{uid}-{token}")
|
||||
|
||||
|
||||
class TokenStorage:
|
||||
@staticmethod
|
||||
async def get(token_key):
|
||||
print('[tokenstorage.get] ' + token_key)
|
||||
# 2041-eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoyMDQxLCJ1c2VybmFtZSI6ImFudG9uLnJld2luK3Rlc3QtbG9hZGNoYXRAZ21haWwuY29tIiwiZXhwIjoxNjcxNzgwNjE2LCJpYXQiOjE2NjkxODg2MTYsImlzcyI6ImRpc2NvdXJzIn0.Nml4oV6iMjMmc6xwM7lTKEZJKBXvJFEIZ-Up1C1rITQ
|
||||
return await redis.execute("GET", token_key)
|
||||
|
||||
@staticmethod
|
||||
|
Reference in New Issue
Block a user