@@ -73,7 +73,6 @@ class UsersService:
73
73
found_user = next (filtered_list)
74
74
if found_user:
75
75
return UserModel(** found_user)
76
- return found_user
77
76
78
77
```
79
78
@@ -95,8 +94,6 @@ class UserModule(ModuleBase):
95
94
User Module
96
95
"""
97
96
98
- pass
99
-
100
97
```
101
98
102
99
### ** Implementing the "Sign in" endpoint**
@@ -191,8 +188,6 @@ class AuthModule(ModuleBase):
191
188
"""
192
189
Auth Module
193
190
"""
194
-
195
- pass
196
191
```
197
192
198
193
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.
443
438
You can also vist [ http://localhost:8000/docs ] ( http://localhost:8000/docs )
444
439
![ Swagger UI] ( ../img/auth_image.png )
445
440
446
- ## Apply AuthGuard Globally
441
+ ## ** Apply AuthGuard Globally**
447
442
448
443
In situations when you need to protect all your endpoints, you can register ` AuthGuard ` as a global guard instead of
449
444
using the ` @UseGuards ` decorator in all your controllers or route functions.
@@ -479,8 +474,6 @@ class AuthModule(ModuleBase):
479
474
"""
480
475
Auth Module
481
476
"""
482
-
483
- pass
484
477
```
485
478
486
479
With this, ` AuthGuard ` will be available to all endpoints.
@@ -613,6 +606,7 @@ class AuthController(ControllerBase):
613
606
async def refresh_token (self , payload : str = Body(embed = True )):
614
607
return await self .auth_service.refresh_token(payload)
615
608
```
609
+ Source Code to this example is [ here] ( )
616
610
617
611
## ** 2. Authentication Schemes**
618
612
@@ -639,8 +633,6 @@ from ellar.common import IHostContext
639
633
from ellar.di import injectable
640
634
from ellar_jwt import JWTService
641
635
642
- from starlette.exceptions import HTTPException
643
-
644
636
645
637
@injectable
646
638
class JWTAuthentication (HttpBearerAuthenticationHandler ):
@@ -657,8 +649,8 @@ class JWTAuthentication(HttpBearerAuthenticationHandler):
657
649
data = await self .jwt_service.decode_async(credentials.credentials)
658
650
return UserIdentity(auth_type = self .scheme, ** data)
659
651
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
662
654
```
663
655
664
656
Let us make ` JWTAuthentication ` Handler available for ellar to use as shown below
@@ -680,46 +672,31 @@ application.add_authentication_schemes(JWTAuthentication)
680
672
681
673
```
682
674
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.
684
677
685
678
!!!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 ` .
687
682
But if you don't have any need for DI injection, you can use the below.
688
683
```python
689
684
...
690
685
application.add_authentication_schemes(JWTAuthentication())
691
686
```
692
687
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.
715
691
716
692
``` python title='auth.controller.py' linenums='1'
717
693
from ellar.common import Controller, ControllerBase, post, Body, get
718
- from ellar.auth import SkipAuth
694
+ from ellar.auth import SkipAuth, AuthenticationRequired
719
695
from ellar.openapi import ApiTags
720
696
from .services import AuthService
721
697
722
698
699
+ @AuthenticationRequired (' JWTAuthentication' )
723
700
@Controller
724
701
@ApiTags (name = ' Authentication' , description = ' User Authentication Endpoints' )
725
702
class AuthController (ControllerBase ):
@@ -742,6 +719,50 @@ class AuthController(ControllerBase):
742
719
743
720
744
721
```
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
+
745
766
Still having the server running, we can test as before
746
767
747
768
``` shell
@@ -758,3 +779,4 @@ $ curl http://localhost:8000/auth/profile -H "Authorization: Bearer eyJhbGciOiJI
758
779
{" exp" :1698793558," iat" :1698793258," jti" :" e96e94c5c3ef4fbbbd7c2468eb64534b" ," sub" :1," user_id" :1," username" :" john" , " id" :null," auth_type" :" bearer" }
759
780
760
781
```
782
+ Source Code to this example is [ here] ( )
0 commit comments