Ajout JWTAuthenticationBackend (from https://github.com/amitripshtos/starlette-jwt/blob/master/starlette_jwt/middleware.py).
This commit is contained in:
parent
d1e3198441
commit
dada376016
|
@ -136,3 +136,5 @@ dmypy.json
|
||||||
|
|
||||||
# Cython debug symbols
|
# Cython debug symbols
|
||||||
cython_debug/
|
cython_debug/
|
||||||
|
|
||||||
|
domains/
|
||||||
|
|
|
@ -9,9 +9,10 @@ from starlette.exceptions import HTTPException
|
||||||
from starlette.middleware import Middleware
|
from starlette.middleware import Middleware
|
||||||
from starlette.middleware.base import BaseHTTPMiddleware
|
from starlette.middleware.base import BaseHTTPMiddleware
|
||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
from starlette.responses import Response
|
from starlette.responses import Response, JSONResponse
|
||||||
from starlette.routing import Route, Match, Mount
|
from starlette.routing import Route, Match, Mount
|
||||||
from starlette.types import ASGIApp, Receive, Scope, Send
|
from starlette.types import ASGIApp, Receive, Scope, Send
|
||||||
|
from starlette.middleware.authentication import AuthenticationMiddleware
|
||||||
|
|
||||||
# typing
|
# typing
|
||||||
from typing import Any, Awaitable, Callable, MutableMapping
|
from typing import Any, Awaitable, Callable, MutableMapping
|
||||||
|
@ -26,6 +27,7 @@ from .models.api.view.route import Route as RouteView
|
||||||
|
|
||||||
# module libraries
|
# module libraries
|
||||||
from .lib.responses import ForbiddenResponse, NotFoundResponse
|
from .lib.responses import ForbiddenResponse, NotFoundResponse
|
||||||
|
from .lib.jwt_middleware import JWTAuthenticationBackend
|
||||||
|
|
||||||
def match_route(app: ASGIApp, scope: Scope):
|
def match_route(app: ASGIApp, scope: Scope):
|
||||||
""" Checks all routes from "app" and checks if it matches with the one from
|
""" Checks all routes from "app" and checks if it matches with the one from
|
||||||
|
@ -215,7 +217,13 @@ def startup():
|
||||||
sys.stderr.write(str(e))
|
sys.stderr.write(str(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
async def root(request):
|
||||||
|
return JSONResponse({'payload': request.payload})
|
||||||
|
|
||||||
app = Starlette(
|
app = Starlette(
|
||||||
middleware=[Middleware(AclCallerMiddleware)],
|
middleware=[
|
||||||
on_startup=[startup]
|
Middleware(AuthenticationMiddleware, backend=JWTAuthenticationBackend(secret_key=open('/etc/half_orm/secret').read())),
|
||||||
|
Middleware(AclCallerMiddleware),
|
||||||
|
],
|
||||||
|
on_startup=[startup],
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
__LICENSE__ = """
|
||||||
|
BSD 3-Clause License
|
||||||
|
|
||||||
|
Copyright (c) 2018, Amit Ripshtos
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holder nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived from
|
||||||
|
this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import jwt
|
||||||
|
from uuid import UUID
|
||||||
|
from starlette.authentication import (
|
||||||
|
AuthenticationBackend, AuthenticationError, BaseUser, AuthCredentials,
|
||||||
|
UnauthenticatedUser)
|
||||||
|
|
||||||
|
|
||||||
|
class JWTUser(BaseUser):
|
||||||
|
def __init__(self, id: UUID, token: str, payload: dict) -> None:
|
||||||
|
self.__id = id
|
||||||
|
self.token = token
|
||||||
|
self.payload = payload
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_authenticated(self) -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def id(self) -> str:
|
||||||
|
return self.id
|
||||||
|
|
||||||
|
|
||||||
|
class JWTAuthenticationBackend(AuthenticationBackend):
|
||||||
|
|
||||||
|
def __init__(self, secret_key: str, algorithm: str = 'HS256', prefix: str = 'JWT', name: str = 'name'):
|
||||||
|
self.secret_key = secret_key
|
||||||
|
self.algorithm = algorithm
|
||||||
|
self.prefix = prefix
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
async def authenticate(self, request):
|
||||||
|
if "Authorization" not in request.headers:
|
||||||
|
return None
|
||||||
|
|
||||||
|
token = request.headers["Authorization"]
|
||||||
|
try:
|
||||||
|
payload = jwt.decode(token, key=self.secret_key, algorithms=self.algorithm)
|
||||||
|
except jwt.InvalidTokenError as e:
|
||||||
|
raise AuthenticationError(str(e))
|
||||||
|
|
||||||
|
return AuthCredentials(["authenticated"]), JWTUser(
|
||||||
|
id=payload['id'], token=token, payload=payload)
|
||||||
|
|
||||||
|
|
||||||
|
class JWTWebSocketAuthenticationBackend(AuthenticationBackend):
|
||||||
|
|
||||||
|
def __init__(self, secret_key: str, algorithm: str = 'HS256', query_param_name: str = 'jwt',
|
||||||
|
id: UUID = None, audience = None, options = {}):
|
||||||
|
self.secret_key = secret_key
|
||||||
|
self.algorithm = algorithm
|
||||||
|
self.query_param_name = query_param_name
|
||||||
|
self.id = id
|
||||||
|
self.audience = audience
|
||||||
|
self.options = options
|
||||||
|
|
||||||
|
|
||||||
|
async def authenticate(self, request):
|
||||||
|
if self.query_param_name not in request.query_params:
|
||||||
|
return AuthCredentials(), UnauthenticatedUser()
|
||||||
|
|
||||||
|
token = request.query_params[self.query_param_name]
|
||||||
|
|
||||||
|
try:
|
||||||
|
payload = jwt.decode(token, key=self.secret_key, algorithms=self.algorithm,
|
||||||
|
audience=self.audience, options=self.options)
|
||||||
|
except jwt.InvalidTokenError as e:
|
||||||
|
raise AuthenticationError(str(e))
|
||||||
|
|
||||||
|
return AuthCredentials(["authenticated"]), JWTUser(id = payload['id'],
|
||||||
|
token=token, payload=payload)
|
|
@ -1,4 +1,5 @@
|
||||||
starlette
|
starlette
|
||||||
uvicorn
|
uvicorn
|
||||||
|
jwt
|
||||||
half_orm @ git+ssh://git@gite.lirmm.fr/newsi/halfORM.git
|
half_orm @ git+ssh://git@gite.lirmm.fr/newsi/halfORM.git
|
||||||
apidb @ git+ssh://git@gite.lirmm.fr/newsi/db/hop_api.git
|
apidb @ git+ssh://git@gite.lirmm.fr/newsi/db/hop_api.git
|
||||||
|
|
Loading…
Reference in New Issue