Skip to content

Commit 520dc94

Browse files
committed
Made some correction on doc and code refactor
1 parent 916a186 commit 520dc94

File tree

2 files changed

+60
-51
lines changed

2 files changed

+60
-51
lines changed

docs/security/authentication.md

Lines changed: 59 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ class UsersService:
7373
found_user = next(filtered_list)
7474
if found_user:
7575
return UserModel(**found_user)
76-
return found_user
7776

7877
```
7978

@@ -95,8 +94,6 @@ class UserModule(ModuleBase):
9594
User Module
9695
"""
9796

98-
pass
99-
10097
```
10198

10299
### **Implementing the "Sign in" endpoint**
@@ -191,8 +188,6 @@ class AuthModule(ModuleBase):
191188
"""
192189
Auth Module
193190
"""
194-
195-
pass
196191
```
197192

198193
In the above example, we configured `JWTModule` with very minimal configurations and registered it as a module dependency
@@ -443,7 +438,7 @@ With the above illustration refresh token mechanism is complete.
443438
You can also vist [http://localhost:8000/docs](http://localhost:8000/docs)
444439
![Swagger UI](../img/auth_image.png)
445440

446-
## Apply AuthGuard Globally
441+
## **Apply AuthGuard Globally**
447442

448443
In situations when you need to protect all your endpoints, you can register `AuthGuard` as a global guard instead of
449444
using the `@UseGuards` decorator in all your controllers or route functions.
@@ -479,8 +474,6 @@ class AuthModule(ModuleBase):
479474
"""
480475
Auth Module
481476
"""
482-
483-
pass
484477
```
485478

486479
With this, `AuthGuard` will be available to all endpoints.
@@ -613,6 +606,7 @@ class AuthController(ControllerBase):
613606
async def refresh_token(self, payload: str = Body(embed=True)):
614607
return await self.auth_service.refresh_token(payload)
615608
```
609+
Source Code to this example is [here]()
616610

617611
## **2. Authentication Schemes**
618612

@@ -639,8 +633,6 @@ from ellar.common import IHostContext
639633
from ellar.di import injectable
640634
from ellar_jwt import JWTService
641635

642-
from starlette.exceptions import HTTPException
643-
644636

645637
@injectable
646638
class JWTAuthentication(HttpBearerAuthenticationHandler):
@@ -657,8 +649,8 @@ class JWTAuthentication(HttpBearerAuthenticationHandler):
657649
data = await self.jwt_service.decode_async(credentials.credentials)
658650
return UserIdentity(auth_type=self.scheme, **data)
659651
except Exception as ex:
660-
# if we cant identity the user or token has expired we raise 401 error.
661-
raise HTTPException(status_code=401) from ex
652+
# if we cant identity the user or token has expired, we return None.
653+
return None
662654
```
663655

664656
Let us make `JWTAuthentication` Handler available for ellar to use as shown below
@@ -680,46 +672,31 @@ application.add_authentication_schemes(JWTAuthentication)
680672

681673
```
682674
Unlike guards, Authentication handlers are registered global by default as shown in the above illustration.
683-
Also, we need to remove `GlobalGuard` registration we did in `AuthModule`, so that we dont have too user identification checks.
675+
Also, we need to remove `GlobalGuard` registration we did in `AuthModule`,
676+
so that we don't have too user identification checks.
684677

685678
!!!note
686-
In the above illustration, we added JWTAuthentication as a type. This means JWTAuthentication instance will be created by DI. We can using this method because we want to inject `JWTService`.
679+
In the above illustration, we added JWTAuthentication as a type.
680+
This means DI will create JWTAuthentication instance.
681+
We can use this method because we want `JWTService` to be injected when instantiating `JWTAuthentication`.
687682
But if you don't have any need for DI injection, you can use the below.
688683
```python
689684
...
690685
application.add_authentication_schemes(JWTAuthentication())
691686
```
692687

693-
Next, we register a simple guard `AuthenticationRequiredGuard` globally to the application. `AuthenticationRequiredGuard` is a simply guard
694-
that checks if a request has a valid user identity.
695-
696-
```python title='project_name.server.py' linenums='1'
697-
import os
698-
from ellar.common.constants import ELLAR_CONFIG_MODULE
699-
from ellar.core.factory import AppFactory
700-
from ellar.auth.guard import AuthenticatedRequiredGuard
701-
from .root_module import ApplicationModule
702-
from .auth_scheme import JWTAuthentication
703-
704-
705-
application = AppFactory.create_from_app_module(
706-
ApplicationModule,
707-
config_module=os.environ.get(
708-
ELLAR_CONFIG_MODULE, "project_name.config:DevelopmentConfig"
709-
),
710-
global_guards=[AuthenticatedRequiredGuard('JWTAuthentication')]
711-
)
712-
application.add_authentication_schemes(JWTAuthentication)
713-
```
714-
We need to refactor auth controller and mark refresh and sign_in function as public routes
688+
We need
689+
to refactor auth controller and mark `refresh_token` and `sign_in` function as public routes
690+
by using `SkipAuth` decorator from `ellar.auth` package.
715691

716692
```python title='auth.controller.py' linenums='1'
717693
from ellar.common import Controller, ControllerBase, post, Body, get
718-
from ellar.auth import SkipAuth
694+
from ellar.auth import SkipAuth, AuthenticationRequired
719695
from ellar.openapi import ApiTags
720696
from .services import AuthService
721697

722698

699+
@AuthenticationRequired('JWTAuthentication')
723700
@Controller
724701
@ApiTags(name='Authentication', description='User Authentication Endpoints')
725702
class AuthController(ControllerBase):
@@ -742,6 +719,50 @@ class AuthController(ControllerBase):
742719

743720

744721
```
722+
In the above illustration,
723+
we decorated AuthController with `@AuthenticationRequired('JWTAuthentication')`
724+
to ensure we have authenticated user before executing any route function and,
725+
we passed in `JWTAuthentication` as a parameter,
726+
which will be used in openapi doc to define the controller routes security scheme.
727+
728+
It is importance to note that when using `AuthenticationHandler` approach,
729+
that you have
730+
to always use `AuthenticationRequired` decorator on route functions or controller
731+
that needs protected from anonymous users.
732+
733+
But if you have a single form of authentication,
734+
you can register `AuthenticatedRequiredGuard` from `eellar.auth.guard` module globally
735+
just like we did in [applying guard globally](#apply-authguard-globally)
736+
737+
```python title='auth.module.py' linenums='1'
738+
from datetime import timedelta
739+
from ellar.auth.guard import AuthenticatedRequiredGuard
740+
from ellar.common import GlobalGuard, Module
741+
from ellar.core import ModuleBase
742+
from ellar.di import ProviderConfig
743+
from ellar_jwt import JWTModule
744+
745+
from ..users.module import UsersModule
746+
from .controllers import AuthController
747+
from .services import AuthService
748+
749+
750+
@Module(
751+
modules=[
752+
UsersModule,
753+
JWTModule.setup(
754+
signing_secret_key="my_poor_secret_key_lol", lifetime=timedelta(minutes=5)
755+
),
756+
],
757+
controllers=[AuthController],
758+
providers=[AuthService, ProviderConfig(GlobalGuard, use_value=AuthenticatedRequiredGuard('JWTAuthentication', []))],
759+
)
760+
class AuthModule(ModuleBase):
761+
"""
762+
Auth Module
763+
"""
764+
```
765+
745766
Still having the server running, we can test as before
746767

747768
```shell
@@ -758,3 +779,4 @@ $ curl http://localhost:8000/auth/profile -H "Authorization: Bearer eyJhbGciOiJI
758779
{"exp":1698793558,"iat":1698793258,"jti":"e96e94c5c3ef4fbbbd7c2468eb64534b","sub":1,"user_id":1,"username":"john", "id":null,"auth_type":"bearer"}
759780

760781
```
782+
Source Code to this example is [here]()

docs/security/authorization.md

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1 @@
1-
# **Authorization**
2-
A
3-
## **`Authorize` and `CheckPolicy` Decorator**
4-
B
5-
## **Policy**
6-
C
7-
## **Policy Combination**
8-
D
9-
## **Default Policies**
10-
E
11-
## **Policy with Requirements**
12-
F
13-
## **Injection in PolicyClasses**
14-
G
1+
# Coming Soon

0 commit comments

Comments
 (0)