django-bolt 0.1.0__cp310-abi3-win_amd64.whl → 0.1.1__cp310-abi3-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-bolt might be problematic. Click here for more details.
- django_bolt/__init__.py +2 -2
- django_bolt/_core.pyd +0 -0
- django_bolt/_json.py +169 -0
- django_bolt/admin/static_routes.py +15 -21
- django_bolt/api.py +181 -61
- django_bolt/auth/__init__.py +2 -2
- django_bolt/decorators.py +15 -3
- django_bolt/dependencies.py +30 -24
- django_bolt/error_handlers.py +2 -1
- django_bolt/openapi/plugins.py +3 -2
- django_bolt/openapi/schema_generator.py +65 -20
- django_bolt/pagination.py +2 -1
- django_bolt/responses.py +3 -2
- django_bolt/serialization.py +5 -4
- {django_bolt-0.1.0.dist-info → django_bolt-0.1.1.dist-info}/METADATA +179 -197
- {django_bolt-0.1.0.dist-info → django_bolt-0.1.1.dist-info}/RECORD +18 -55
- django_bolt/auth/README.md +0 -464
- django_bolt/auth/REVOCATION_EXAMPLE.md +0 -391
- django_bolt/tests/__init__.py +0 -0
- django_bolt/tests/admin_tests/__init__.py +0 -1
- django_bolt/tests/admin_tests/conftest.py +0 -6
- django_bolt/tests/admin_tests/test_admin_with_django.py +0 -278
- django_bolt/tests/admin_tests/urls.py +0 -9
- django_bolt/tests/cbv/__init__.py +0 -0
- django_bolt/tests/cbv/test_class_views.py +0 -570
- django_bolt/tests/cbv/test_class_views_django_orm.py +0 -703
- django_bolt/tests/cbv/test_class_views_features.py +0 -1173
- django_bolt/tests/cbv/test_class_views_with_client.py +0 -622
- django_bolt/tests/conftest.py +0 -165
- django_bolt/tests/test_action_decorator.py +0 -399
- django_bolt/tests/test_auth_secret_key.py +0 -83
- django_bolt/tests/test_decorator_syntax.py +0 -159
- django_bolt/tests/test_error_handling.py +0 -481
- django_bolt/tests/test_file_response.py +0 -192
- django_bolt/tests/test_global_cors.py +0 -172
- django_bolt/tests/test_guards_auth.py +0 -441
- django_bolt/tests/test_guards_integration.py +0 -303
- django_bolt/tests/test_health.py +0 -283
- django_bolt/tests/test_integration_validation.py +0 -400
- django_bolt/tests/test_json_validation.py +0 -536
- django_bolt/tests/test_jwt_auth.py +0 -327
- django_bolt/tests/test_jwt_token.py +0 -458
- django_bolt/tests/test_logging.py +0 -837
- django_bolt/tests/test_logging_merge.py +0 -419
- django_bolt/tests/test_middleware.py +0 -492
- django_bolt/tests/test_middleware_server.py +0 -230
- django_bolt/tests/test_model_viewset.py +0 -323
- django_bolt/tests/test_models.py +0 -24
- django_bolt/tests/test_pagination.py +0 -1258
- django_bolt/tests/test_parameter_validation.py +0 -178
- django_bolt/tests/test_syntax.py +0 -626
- django_bolt/tests/test_testing_utilities.py +0 -163
- django_bolt/tests/test_testing_utilities_simple.py +0 -123
- django_bolt/tests/test_viewset_unified.py +0 -346
- {django_bolt-0.1.0.dist-info → django_bolt-0.1.1.dist-info}/WHEEL +0 -0
- {django_bolt-0.1.0.dist-info → django_bolt-0.1.1.dist-info}/entry_points.txt +0 -0
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
django_bolt-0.1.
|
|
2
|
-
django_bolt-0.1.
|
|
3
|
-
django_bolt-0.1.
|
|
4
|
-
django_bolt/__init__.py,sha256=
|
|
5
|
-
django_bolt/_core.pyd,sha256=
|
|
1
|
+
django_bolt-0.1.1.dist-info/METADATA,sha256=h0ifCk91UOPGcMEaReodmlr2UBdueXw40w4HVUgEA94,21343
|
|
2
|
+
django_bolt-0.1.1.dist-info/WHEEL,sha256=4EDp_7DiFfWl1yYv5M4wSosAn5L_xgD1dyrQxQxfCx8,95
|
|
3
|
+
django_bolt-0.1.1.dist-info/entry_points.txt,sha256=cUEGAdiOY6BryNhsgOS_50AONPPHajI3yvhqr56ZiaU,51
|
|
4
|
+
django_bolt/__init__.py,sha256=fhXQUJR5SO-GwhF_2N9w0UK6rIFx7kWGfpOPyIKvB9Q,3139
|
|
5
|
+
django_bolt/_core.pyd,sha256=iMY9GY4G-NVQHoAtoIHjpukLVrjiqsZZPym6uYGILus,8905728
|
|
6
|
+
django_bolt/_json.py,sha256=oGxi29DHB8UYvbqjtqtrP6gThk7Qonlw333c4_cTr6s,4917
|
|
6
7
|
django_bolt/admin/__init__.py,sha256=BNN1afSvWvt-377rNzZLdNDEvKyMZXkmB_0MhTxAN8k,601
|
|
7
8
|
django_bolt/admin/admin_detection.py,sha256=1yQkLx9rF5DLMjJqbx8n4c82UgS9JEAnUcPdRfFqAXk,5825
|
|
8
9
|
django_bolt/admin/asgi_bridge.py,sha256=oJrOqbBi8w-OUZD_wvpa5FlRFGIOyRvV284z8OS1kiY,9030
|
|
9
10
|
django_bolt/admin/routes.py,sha256=dGrSz6fOwofLuBpNpzyqtcLuGbd4AgSQ2jZub_3cz1Y,3235
|
|
10
11
|
django_bolt/admin/static.py,sha256=eXeOs2VWnxKdLDKarI4eD2q92K9R3JJHW1XQYmAsVDA,4692
|
|
11
|
-
django_bolt/admin/static_routes.py,sha256=
|
|
12
|
-
django_bolt/api.py,sha256=
|
|
12
|
+
django_bolt/admin/static_routes.py,sha256=sdpuCPhULMr5LccVxfbU2XSfpmL8oP7DCXqUpy0cnNY,3512
|
|
13
|
+
django_bolt/api.py,sha256=1wJOg4-fuDzhG9ovHXjA6ONqlEFEvfrjx97xpja4oBU,49386
|
|
13
14
|
django_bolt/apps.py,sha256=OKBK6McSzRZ8zGQaId5iw239QbIgqs8tIbAqpuYxmn0,193
|
|
14
15
|
django_bolt/async_collector.py,sha256=m1U6wjE9wheVMuql8aooR47tkLz_RlADgkIl2p9H6Uw,7749
|
|
15
|
-
django_bolt/auth/
|
|
16
|
-
django_bolt/auth/REVOCATION_EXAMPLE.md,sha256=5gGUt7cMXuzEM4-24J8hZJe8OLZGLp6eN1A7QTSNdrs,11056
|
|
17
|
-
django_bolt/auth/__init__.py,sha256=nIc_P5rXLjOkq3eFyzZ0B6vDmIGWlb-m1LsmF1LISos,1880
|
|
16
|
+
django_bolt/auth/__init__.py,sha256=ygi_SCzH1CNOcQwDe0ZKIe072xBa7zeKVUtUoG0_dwY,1968
|
|
18
17
|
django_bolt/auth/backends.py,sha256=T02zfiC17GZrARKlqzKSnkMOtEcYQDTmS4PouRvsNOU,7944
|
|
19
18
|
django_bolt/auth/guards.py,sha256=Dwbqhq4_I41BoN0eWrQ7Ad9mmr9zgCoPAg4C3GElTio,6591
|
|
20
19
|
django_bolt/auth/jwt_utils.py,sha256=phLKyXQXrqL8TLLZVA-reitOVylSTJ9FKSBETa1_OCg,6518
|
|
@@ -24,9 +23,9 @@ django_bolt/binding.py,sha256=UtmwW55RKyBwNxbX5QQ74NF0EF5k5zaMGa5el7mgljg,12860
|
|
|
24
23
|
django_bolt/bootstrap.py,sha256=zXkVhcDZxluQBWXc_UHK0FfgOfpdgxCg01DmSbSdXos,3007
|
|
25
24
|
django_bolt/cli.py,sha256=0TBGM37cCqKEew_QA26ru7KkR8_6mP5wKXgFhr8GWng,4647
|
|
26
25
|
django_bolt/compression.py,sha256=8ioDa2j0TG_mna-Jh34-e6WjCeY0GSKwRPHMn8en8OQ,4025
|
|
27
|
-
django_bolt/decorators.py,sha256=
|
|
28
|
-
django_bolt/dependencies.py,sha256=
|
|
29
|
-
django_bolt/error_handlers.py,sha256=
|
|
26
|
+
django_bolt/decorators.py,sha256=hvfIZMxZI3S4eo6KYiOiEC-1Z96fSwQxQopLB4jmez0,6656
|
|
27
|
+
django_bolt/dependencies.py,sha256=D_D9onQLMH85q0o4tSeKo0nTiJmx_Hifg3AwwcTfRUM,4443
|
|
28
|
+
django_bolt/error_handlers.py,sha256=uD9_9vnub8FxZCRXgcqOdMic5M8cFD-sPXePdSl9IaY,10032
|
|
30
29
|
django_bolt/exceptions.py,sha256=iYTkmtel7VlpjwuOrijDgt8fsx8_Kd0gezLEdR6CrDs,8823
|
|
31
30
|
django_bolt/health.py,sha256=MBcXlgkTAdEiAvmGRPSgn9iePhH-rcHXan7Ge1EaPog,3356
|
|
32
31
|
django_bolt/logging/__init__.py,sha256=bI71S22rJoMLtGg-ejh6qrlwDaW_lSV0ufxNbDw3NRQ,230
|
|
@@ -40,9 +39,9 @@ django_bolt/middleware/compiler.py,sha256=Knxh3XouU70ymIskDB-JWn1TcHSMPQvUBXtTPH
|
|
|
40
39
|
django_bolt/middleware/middleware.py,sha256=Qdr16OM15oOS1OYNnxFY3hJ0un9E8VaVwht-A8Qcuws,8113
|
|
41
40
|
django_bolt/openapi/__init__.py,sha256=LgvKbDBCGGKBvm6vW0nSmagtXw1CZ2swZf_ElhXIn68,572
|
|
42
41
|
django_bolt/openapi/config.py,sha256=PHqd2LkSUZWpssj7hQHnUhgqKzaARjgKWyPdfEMlxvs,6230
|
|
43
|
-
django_bolt/openapi/plugins.py,sha256=
|
|
42
|
+
django_bolt/openapi/plugins.py,sha256=ncoxieMFzP4YAO4_gaNomcOBd6HZ0z3N-5TBU1d2ZTs,15348
|
|
44
43
|
django_bolt/openapi/routes.py,sha256=08Tn1EA5wjvzJzks7v4oHI5qyrbU9-5KLLkfuij7JfI,6047
|
|
45
|
-
django_bolt/openapi/schema_generator.py,sha256=
|
|
44
|
+
django_bolt/openapi/schema_generator.py,sha256=JtTOccrSXjwcaMPMAftqjPQbzjEmr16kG0OOuaTuEJA,22237
|
|
46
45
|
django_bolt/openapi/spec/__init__.py,sha256=a1ZJNgdoXKZSKOnxThuwhhDYqTBGSlUJU4JElfjtZY0,1759
|
|
47
46
|
django_bolt/openapi/spec/base.py,sha256=qXTjQiKSllTDSTNTvXnxkyYXG4vQZnZU5Ev4jQfyfec,2418
|
|
48
47
|
django_bolt/openapi/spec/callback.py,sha256=mvz71QTtYWQZQheWSsrvyssi3lb-vH7Diqj9Cf71ezg,937
|
|
@@ -76,53 +75,17 @@ django_bolt/openapi/spec/server.py,sha256=wvo84Z7WbV5s8glor5N5ywwM-B7C6YUqS_il0Q
|
|
|
76
75
|
django_bolt/openapi/spec/server_variable.py,sha256=ZEqqp1FWOMARl2YIWrRXtX7AuwnuX5WtlN_63eQ5Jk0,1182
|
|
77
76
|
django_bolt/openapi/spec/tag.py,sha256=uxn6IpNMDaTUdziQNVOMoZq4uAOGGSR1b5DbTcLvm8Y,913
|
|
78
77
|
django_bolt/openapi/spec/xml.py,sha256=WfuYpX_eROu5bmGTeR5x6dK0T0nw6RIJP9Hc-nQBNZ4,1725
|
|
79
|
-
django_bolt/pagination.py,sha256=
|
|
78
|
+
django_bolt/pagination.py,sha256=SUEgNxK4BWLTdNiegJeFoAWSxCAI1au8PO0IYGlGq5Q,22473
|
|
80
79
|
django_bolt/param_functions.py,sha256=GIdm4ti7D40iVzj496ICq9Iu8TPeGVXNCJsODcTs4nE,1120
|
|
81
80
|
django_bolt/params.py,sha256=_7N3_oa0mWuCuh1LKuaBDUS6TIeYWD_wVFrMJ-1L8Yg,8371
|
|
82
81
|
django_bolt/request_parsing.py,sha256=7ZHfD7FkTJYsFSrEsFqmFW7JlC4m-0fAaTx089GXpf4,4818
|
|
83
|
-
django_bolt/responses.py,sha256=
|
|
82
|
+
django_bolt/responses.py,sha256=B0LXHN431c1-o93DC_xTF-wrnv8CMxn-1Sd0Yi4cwjE,7238
|
|
84
83
|
django_bolt/router.py,sha256=wTFsPasg5Sh5hgdFp1kCmUrK6ugwRPWEj7PsxWOc9lc,1532
|
|
85
|
-
django_bolt/serialization.py,sha256=
|
|
84
|
+
django_bolt/serialization.py,sha256=Uza6jzQPTFxTQHnXEWBEDYY-3xDOGZinBSRE0T4KK28,8825
|
|
86
85
|
django_bolt/status_codes.py,sha256=jTZ32kPwj3tC23jh6uC1Ci1P9EKttywsvyWINQIEwGg,9386
|
|
87
86
|
django_bolt/testing/__init__.py,sha256=5UDYTmdyKkkY5ENlOlZcK0twbsLSylpjlp7oFgqNC-0,257
|
|
88
87
|
django_bolt/testing/client.py,sha256=X1DXulzJHuN3RKvyMhEP4yhymc2UrUDBrnngho-m1yA,10008
|
|
89
88
|
django_bolt/testing/helpers.py,sha256=Vv-4KuIbOVfCWQvohKpO37u59uhrhpWnRU5bWzbK5rg,2820
|
|
90
|
-
django_bolt/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
91
|
-
django_bolt/tests/admin_tests/__init__.py,sha256=7n1EF-XwQVo-2VQXFt-W8EosL8l6w6LOJ5Ff3Jkpo_Q,25
|
|
92
|
-
django_bolt/tests/admin_tests/conftest.py,sha256=i8Og6NWC2c-i0p2zuXyeaKzRSZYvntaEJO51OMLdVew,172
|
|
93
|
-
django_bolt/tests/admin_tests/test_admin_with_django.py,sha256=BuRaHpZ_Xt8aHhllhK4XIGsl8_oJxqTslgQ4Bm2Kdbc,9320
|
|
94
|
-
django_bolt/tests/admin_tests/urls.py,sha256=gF111ic0YAEE_2_BEI0LKwmnacVqp4sft955AoH_XXg,182
|
|
95
|
-
django_bolt/tests/cbv/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
96
|
-
django_bolt/tests/cbv/test_class_views.py,sha256=uYx_UHxS2Dxno7MJnDQpXFY5fiJ-TGeaXkk42mXOX2s,16390
|
|
97
|
-
django_bolt/tests/cbv/test_class_views_django_orm.py,sha256=bl_j2fB4IP35BIBPAzvkcfRuHOUFrt61rE3PKG1CpzE,23553
|
|
98
|
-
django_bolt/tests/cbv/test_class_views_features.py,sha256=ub3wmlXnYSF0CUeFMkzr-Tg22lkPIK-BkWtaIV1oqHU,45032
|
|
99
|
-
django_bolt/tests/cbv/test_class_views_with_client.py,sha256=_S3Qkw3T2RhF0Eme4xKQ7HpG1j9goylD9drF2Xotzbg,19410
|
|
100
|
-
django_bolt/tests/conftest.py,sha256=RtuDXQy5tU6FJ_QydNe4rKok2dbXHOIolf4p4iCFqYc,5557
|
|
101
|
-
django_bolt/tests/test_action_decorator.py,sha256=3mhv6Y2MisnoxTM0Fcy0Eqvlsn4ucRnFOwB6bK2bKQc,13002
|
|
102
|
-
django_bolt/tests/test_auth_secret_key.py,sha256=GZzqCYmr8O20cBELttK59vUgRGsy1TDjHXsCPspz-cw,2915
|
|
103
|
-
django_bolt/tests/test_decorator_syntax.py,sha256=LtcINgNxs8dIP1Ryl7lTwaxH7u8-BQRCdjCk0DJZg1A,4512
|
|
104
|
-
django_bolt/tests/test_error_handling.py,sha256=RI0CEz02jSoH6wUZ-xNs2X0M8MROOyqhfx2SoAY3UC8,18260
|
|
105
|
-
django_bolt/tests/test_file_response.py,sha256=ydBfSPk5YvblWArPiI24gSMuJtJR4kmdClNNs-_Ltxg,6190
|
|
106
|
-
django_bolt/tests/test_global_cors.py,sha256=sf51Lj50Xklzy6-EXMOlF40VGYszTD34V17W3ypmAog,6451
|
|
107
|
-
django_bolt/tests/test_guards_auth.py,sha256=bLwVCjfJBemgd8ksO7Su1efdVLOvX7bdZI7VMEN-WCs,15202
|
|
108
|
-
django_bolt/tests/test_guards_integration.py,sha256=PFXNt3zwZH5PH3IeCiLr8dNSrjFTJw_M7kPvavqhJ_Y,10744
|
|
109
|
-
django_bolt/tests/test_health.py,sha256=IgGfkizK-20hIFi56PygjcLtkQToxWZ6aI683-dQVn8,9092
|
|
110
|
-
django_bolt/tests/test_integration_validation.py,sha256=QkHJuHliWzDmx7A3t6Lkr-ONuWDYv1uScs2DHIowp8E,14013
|
|
111
|
-
django_bolt/tests/test_json_validation.py,sha256=zTQCZMTnzMiFTABDD0XhjU0uYYmmNoNZbtEjr_VnwdU,19615
|
|
112
|
-
django_bolt/tests/test_jwt_auth.py,sha256=F3poh-a9uGKYLi4rGgtCYc92nLbDrxjst-Vl15gKN5s,9851
|
|
113
|
-
django_bolt/tests/test_jwt_token.py,sha256=iOaa9_iZofSrv952lQfRyyNnkhmLx_bwSowYPIu2--A,15735
|
|
114
|
-
django_bolt/tests/test_logging.py,sha256=zpzx3GP8G0o7jbwXMy6_CvF9c86SOvaQa05nDdytNEw,35751
|
|
115
|
-
django_bolt/tests/test_logging_merge.py,sha256=sGELEpWWhVBP5HXKTJjtVX7CF6ZzUeAlrcr6tWJLcGY,16226
|
|
116
|
-
django_bolt/tests/test_middleware.py,sha256=kIqcICLNSA5S8-mnyH_hvzx3YutPtpYYl8RzsUu_888,17091
|
|
117
|
-
django_bolt/tests/test_middleware_server.py,sha256=HoRrroK8a6iusAOwnsEE7nR0vzZO5kW830JGJ3NZyKg,7810
|
|
118
|
-
django_bolt/tests/test_model_viewset.py,sha256=b7x60ftTMwdCPprsiztWpU6KwWcG0-Fn2LevlYcbETw,11061
|
|
119
|
-
django_bolt/tests/test_models.py,sha256=BuKmNOb-BkwBry_vUOZF2jFABZ1uh-vi_O9EiQRurxk,717
|
|
120
|
-
django_bolt/tests/test_pagination.py,sha256=7hueeu7e5k2ZiZ6fvFilYEUsxqM5NTTFM0Uay8UvYLQ,39823
|
|
121
|
-
django_bolt/tests/test_parameter_validation.py,sha256=M2Nr-WNOuUhv91I0RYBzjtv3wkYJSsTAQSSV1CoSXg4,5538
|
|
122
|
-
django_bolt/tests/test_syntax.py,sha256=IyyP9q0w-poVxUrSOk2tsEHl9nx1ERs25ugmgZqaY2o,22071
|
|
123
|
-
django_bolt/tests/test_testing_utilities.py,sha256=39w47yO6lE_FYWWDnQP24T-fkftJL2mZclWi2ZTNUvw,4787
|
|
124
|
-
django_bolt/tests/test_testing_utilities_simple.py,sha256=sBaLWG0pb_-pyVjG8_StkBxIWCWdzTsV5LRkkV53cLQ,4223
|
|
125
|
-
django_bolt/tests/test_viewset_unified.py,sha256=G-yWkvr9byXPOJGuVQhWe7XpSGnffXoxOTguJTyy3ZY,12219
|
|
126
89
|
django_bolt/typing.py,sha256=sGlFUUXY8EJbYWCgARgNGLZPu7SaxxohZaSx1SRLYaE,8686
|
|
127
90
|
django_bolt/views.py,sha256=KewSpL6g-zZxXnEkwun6hueX3S_Eji-d2dawzoqe-GM,41715
|
|
128
|
-
django_bolt-0.1.
|
|
91
|
+
django_bolt-0.1.1.dist-info/RECORD,,
|
django_bolt/auth/README.md
DELETED
|
@@ -1,464 +0,0 @@
|
|
|
1
|
-
# Django-Bolt Authentication System
|
|
2
|
-
|
|
3
|
-
High-performance authentication and authorization system where **validation happens in Rust without the GIL**, achieving 60k+ RPS with JWT authentication.
|
|
4
|
-
|
|
5
|
-
## Architecture
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
9
|
-
│ Python Layer (Configuration) │
|
|
10
|
-
│ │
|
|
11
|
-
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
12
|
-
│ │ JWTAuth │ │ APIKeyAuth │ │ Guards │ │
|
|
13
|
-
│ │ │ │ │ │ │ │
|
|
14
|
-
│ │ .to_metadata()│ │ .to_metadata()│ │ .to_metadata()│ │
|
|
15
|
-
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
|
|
16
|
-
│ │ │ │ │
|
|
17
|
-
│ └──────────────────┴──────────────────┘ │
|
|
18
|
-
│ │ │
|
|
19
|
-
│ Compile to metadata │
|
|
20
|
-
│ │ │
|
|
21
|
-
└────────────────────────────┼─────────────────────────────────────┘
|
|
22
|
-
│
|
|
23
|
-
▼
|
|
24
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
25
|
-
│ Rust Layer (Validation - NO GIL) │
|
|
26
|
-
│ │
|
|
27
|
-
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
28
|
-
│ │ Route Registration │ │
|
|
29
|
-
│ │ • Parse metadata → typed Rust enums │ │
|
|
30
|
-
│ │ • Store auth backends & guards per route │ │
|
|
31
|
-
│ └──────────────────────────────────────────────────────────┘ │
|
|
32
|
-
│ │
|
|
33
|
-
│ ┌──────────────────────────────────────────────────────────┐ │
|
|
34
|
-
│ │ Request Processing (HOT PATH - NO GIL) │ │
|
|
35
|
-
│ │ │ │
|
|
36
|
-
│ │ 1. Extract token from header │ │
|
|
37
|
-
│ │ 2. Validate JWT (jsonwebtoken crate) │ │
|
|
38
|
-
│ │ 3. Check guards/permissions │ │
|
|
39
|
-
│ │ 4. Populate request.context with auth data │ │
|
|
40
|
-
│ │ │ │
|
|
41
|
-
│ │ ⚡ All happens without touching Python/GIL │ │
|
|
42
|
-
│ └──────────────────────────────────────────────────────────┘ │
|
|
43
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
44
|
-
│
|
|
45
|
-
▼
|
|
46
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
47
|
-
│ Python Handler (WITH AuthContext) │
|
|
48
|
-
│ │
|
|
49
|
-
│ async def my_handler(request): │
|
|
50
|
-
│ user_id = request["context"]["user_id"] │
|
|
51
|
-
│ is_admin = request["context"]["is_admin"] │
|
|
52
|
-
│ permissions = request["context"]["permissions"] │
|
|
53
|
-
│ claims = request["context"]["auth_claims"] │
|
|
54
|
-
│ ... │
|
|
55
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
## Module Structure
|
|
59
|
-
|
|
60
|
-
```
|
|
61
|
-
django_bolt/auth/
|
|
62
|
-
├── __init__.py # Public API exports
|
|
63
|
-
├── README.md # This file
|
|
64
|
-
├── backends.py # Authentication backends (JWT, API key, Session)
|
|
65
|
-
├── guards.py # Permission guards (IsAuthenticated, IsAdmin, etc.)
|
|
66
|
-
├── middleware.py # Middleware decorators (cors, rate_limit, etc.)
|
|
67
|
-
└── token.py # JWT Token dataclass with encode/decode
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Quick Start
|
|
71
|
-
|
|
72
|
-
### 1. Define Authentication Backend
|
|
73
|
-
|
|
74
|
-
```python
|
|
75
|
-
from django_bolt import BoltAPI, JWTAuthentication, IsAuthenticated, Token
|
|
76
|
-
from datetime import timedelta
|
|
77
|
-
|
|
78
|
-
api = BoltAPI()
|
|
79
|
-
|
|
80
|
-
# Create JWT token for a user
|
|
81
|
-
def create_token_for_user(user):
|
|
82
|
-
return Token.create(
|
|
83
|
-
sub=str(user.id),
|
|
84
|
-
expires_delta=timedelta(hours=1),
|
|
85
|
-
is_staff=user.is_staff,
|
|
86
|
-
is_admin=user.is_superuser,
|
|
87
|
-
permissions=list(user.get_all_permissions()),
|
|
88
|
-
email=user.email,
|
|
89
|
-
).encode(secret=settings.SECRET_KEY)
|
|
90
|
-
|
|
91
|
-
# Protected endpoint
|
|
92
|
-
@api.get(
|
|
93
|
-
"/profile",
|
|
94
|
-
auth=[JWTAuthentication()],
|
|
95
|
-
guards=[IsAuthenticated()]
|
|
96
|
-
)
|
|
97
|
-
async def get_profile(request):
|
|
98
|
-
user_id = request["context"]["user_id"]
|
|
99
|
-
is_admin = request["context"]["is_admin"]
|
|
100
|
-
|
|
101
|
-
return {
|
|
102
|
-
"user_id": user_id,
|
|
103
|
-
"is_admin": is_admin,
|
|
104
|
-
"permissions": request["context"].get("permissions", [])
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
### 2. Global Authentication (Settings)
|
|
109
|
-
|
|
110
|
-
```python
|
|
111
|
-
# settings.py
|
|
112
|
-
|
|
113
|
-
BOLT_AUTHENTICATION_CLASSES = [
|
|
114
|
-
JWTAuthentication(
|
|
115
|
-
secret=SECRET_KEY,
|
|
116
|
-
algorithms=["HS256"],
|
|
117
|
-
header="authorization",
|
|
118
|
-
audience="my-api",
|
|
119
|
-
)
|
|
120
|
-
]
|
|
121
|
-
|
|
122
|
-
BOLT_DEFAULT_PERMISSION_CLASSES = [
|
|
123
|
-
IsAuthenticated()
|
|
124
|
-
]
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Now all routes are protected by default unless you override with `guards=[AllowAny()]`.
|
|
128
|
-
|
|
129
|
-
### 3. Per-Route Authentication Override
|
|
130
|
-
|
|
131
|
-
```python
|
|
132
|
-
from django_bolt import APIKeyAuthentication, HasPermission
|
|
133
|
-
|
|
134
|
-
# Admin-only endpoint with API key auth
|
|
135
|
-
@api.delete(
|
|
136
|
-
"/users/{user_id}",
|
|
137
|
-
auth=[APIKeyAuthentication(api_keys={"admin-key-123"})],
|
|
138
|
-
guards=[HasPermission("users.delete")]
|
|
139
|
-
)
|
|
140
|
-
async def delete_user(user_id: int):
|
|
141
|
-
# Only callable with valid API key and users.delete permission
|
|
142
|
-
return {"deleted": user_id}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## Authentication Backends
|
|
146
|
-
|
|
147
|
-
### JWTAuthentication
|
|
148
|
-
|
|
149
|
-
High-performance JWT validation in Rust using the `jsonwebtoken` crate.
|
|
150
|
-
|
|
151
|
-
```python
|
|
152
|
-
from django_bolt import JWTAuthentication
|
|
153
|
-
|
|
154
|
-
auth = JWTAuthentication(
|
|
155
|
-
secret="your-secret-key", # Default: Django SECRET_KEY
|
|
156
|
-
algorithms=["HS256"], # Supported: HS256/384/512, RS256/384/512, ES256/384
|
|
157
|
-
header="authorization", # Header to extract token from
|
|
158
|
-
audience="my-api", # Optional: validate aud claim
|
|
159
|
-
issuer="auth-service", # Optional: validate iss claim
|
|
160
|
-
)
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
**Token Format**: `Authorization: Bearer <jwt-token>`
|
|
164
|
-
|
|
165
|
-
**Performance**: ~60k RPS with JWT validation
|
|
166
|
-
|
|
167
|
-
### APIKeyAuthentication
|
|
168
|
-
|
|
169
|
-
Simple API key validation with optional per-key permissions.
|
|
170
|
-
|
|
171
|
-
```python
|
|
172
|
-
from django_bolt import APIKeyAuthentication
|
|
173
|
-
|
|
174
|
-
auth = APIKeyAuthentication(
|
|
175
|
-
api_keys={"key1", "key2", "admin-key"},
|
|
176
|
-
header="x-api-key",
|
|
177
|
-
key_permissions={
|
|
178
|
-
"admin-key": ["users.create", "users.delete", "posts.create"],
|
|
179
|
-
"key1": ["users.view"],
|
|
180
|
-
"key2": ["posts.view", "posts.create"],
|
|
181
|
-
}
|
|
182
|
-
)
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
**Header Format**: `X-API-Key: your-api-key`
|
|
186
|
-
|
|
187
|
-
### SessionAuthentication
|
|
188
|
-
|
|
189
|
-
Django session-based authentication (falls back to Python execution).
|
|
190
|
-
|
|
191
|
-
```python
|
|
192
|
-
from django_bolt import SessionAuthentication
|
|
193
|
-
|
|
194
|
-
auth = SessionAuthentication()
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
**Note**: This has higher overhead than JWT/API key as it requires Python execution per request.
|
|
198
|
-
|
|
199
|
-
## Permission Guards
|
|
200
|
-
|
|
201
|
-
Guards are checked **after authentication** in Rust, providing early 403 responses without GIL overhead.
|
|
202
|
-
|
|
203
|
-
### AllowAny
|
|
204
|
-
|
|
205
|
-
Allow unauthenticated requests (bypasses global defaults).
|
|
206
|
-
|
|
207
|
-
```python
|
|
208
|
-
from django_bolt import AllowAny
|
|
209
|
-
|
|
210
|
-
@api.get("/public", guards=[AllowAny()])
|
|
211
|
-
async def public_endpoint():
|
|
212
|
-
return {"message": "Anyone can access this"}
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### IsAuthenticated
|
|
216
|
-
|
|
217
|
-
Require valid authentication (any backend).
|
|
218
|
-
|
|
219
|
-
```python
|
|
220
|
-
from django_bolt import IsAuthenticated
|
|
221
|
-
|
|
222
|
-
@api.get("/protected", guards=[IsAuthenticated()])
|
|
223
|
-
async def protected():
|
|
224
|
-
return {"message": "Must be authenticated"}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### IsAdminUser / IsStaff
|
|
228
|
-
|
|
229
|
-
Require admin or staff status (from JWT claims `is_superuser`, `is_admin`, or `is_staff`).
|
|
230
|
-
|
|
231
|
-
```python
|
|
232
|
-
from django_bolt import IsAdminUser, IsStaff
|
|
233
|
-
|
|
234
|
-
@api.get("/admin", guards=[IsAdminUser()])
|
|
235
|
-
async def admin_only():
|
|
236
|
-
return {"message": "Admin access"}
|
|
237
|
-
|
|
238
|
-
@api.get("/staff", guards=[IsStaff()])
|
|
239
|
-
async def staff_only():
|
|
240
|
-
return {"message": "Staff access"}
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### HasPermission / HasAnyPermission / HasAllPermissions
|
|
244
|
-
|
|
245
|
-
Fine-grained permission checking.
|
|
246
|
-
|
|
247
|
-
```python
|
|
248
|
-
from django_bolt import HasPermission, HasAnyPermission, HasAllPermissions
|
|
249
|
-
|
|
250
|
-
# Require specific permission
|
|
251
|
-
@api.delete("/users/{id}", guards=[HasPermission("users.delete")])
|
|
252
|
-
async def delete_user(id: int):
|
|
253
|
-
pass
|
|
254
|
-
|
|
255
|
-
# Require at least one permission
|
|
256
|
-
@api.put("/users/{id}", guards=[HasAnyPermission("users.edit", "users.admin")])
|
|
257
|
-
async def edit_user(id: int):
|
|
258
|
-
pass
|
|
259
|
-
|
|
260
|
-
# Require all permissions
|
|
261
|
-
@api.post("/admin/reset", guards=[HasAllPermissions("admin.full", "admin.reset")])
|
|
262
|
-
async def reset_system():
|
|
263
|
-
pass
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
## JWT Token Class
|
|
267
|
-
|
|
268
|
-
The `Token` dataclass provides a Pythonic interface for JWT tokens with validation.
|
|
269
|
-
|
|
270
|
-
### Creating Tokens
|
|
271
|
-
|
|
272
|
-
```python
|
|
273
|
-
from django_bolt import Token
|
|
274
|
-
from datetime import datetime, timedelta, timezone
|
|
275
|
-
|
|
276
|
-
# Option 1: Direct instantiation
|
|
277
|
-
token = Token(
|
|
278
|
-
sub="user123",
|
|
279
|
-
exp=datetime.now(timezone.utc) + timedelta(hours=1),
|
|
280
|
-
is_staff=True,
|
|
281
|
-
permissions=["read", "write"],
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
# Option 2: Factory method (recommended)
|
|
285
|
-
token = Token.create(
|
|
286
|
-
sub="user123",
|
|
287
|
-
expires_delta=timedelta(hours=1),
|
|
288
|
-
is_staff=True,
|
|
289
|
-
is_admin=False,
|
|
290
|
-
permissions=["users.view", "posts.create"],
|
|
291
|
-
# Extra custom claims
|
|
292
|
-
tenant_id="acme-corp",
|
|
293
|
-
role="manager",
|
|
294
|
-
)
|
|
295
|
-
|
|
296
|
-
# Encode to JWT string
|
|
297
|
-
jwt_string = token.encode(secret="my-secret", algorithm="HS256")
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### Decoding Tokens
|
|
301
|
-
|
|
302
|
-
```python
|
|
303
|
-
# Decode and validate
|
|
304
|
-
token = Token.decode(
|
|
305
|
-
jwt_string,
|
|
306
|
-
secret="my-secret",
|
|
307
|
-
algorithm="HS256",
|
|
308
|
-
audience="my-api", # Optional
|
|
309
|
-
issuer="auth-service", # Optional
|
|
310
|
-
verify_exp=True, # Verify expiration
|
|
311
|
-
verify_nbf=True, # Verify not-before
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
print(token.sub) # "user123"
|
|
315
|
-
print(token.is_staff) # True
|
|
316
|
-
print(token.permissions) # ["users.view", "posts.create"]
|
|
317
|
-
print(token.extras) # {"tenant_id": "acme-corp", "role": "manager"}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
### Integration with Django Users
|
|
321
|
-
|
|
322
|
-
```python
|
|
323
|
-
from django_bolt.jwt_utils import create_jwt_for_user
|
|
324
|
-
|
|
325
|
-
# Create token from Django User instance
|
|
326
|
-
user = await User.objects.aget(username="john")
|
|
327
|
-
token = create_jwt_for_user(
|
|
328
|
-
user,
|
|
329
|
-
expires_in=3600, # 1 hour
|
|
330
|
-
extra_claims={
|
|
331
|
-
"permissions": ["users.view", "posts.create"],
|
|
332
|
-
"tenant": "acme",
|
|
333
|
-
}
|
|
334
|
-
)
|
|
335
|
-
|
|
336
|
-
# Use in login endpoint
|
|
337
|
-
@api.post("/login")
|
|
338
|
-
async def login(username: str, password: str):
|
|
339
|
-
# Authenticate user...
|
|
340
|
-
token = create_jwt_for_user(user)
|
|
341
|
-
return {"access_token": token, "token_type": "bearer"}
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
## Request Context
|
|
345
|
-
|
|
346
|
-
After authentication, the request context is populated with auth data:
|
|
347
|
-
|
|
348
|
-
```python
|
|
349
|
-
@api.get("/me")
|
|
350
|
-
async def get_current_user_info(request):
|
|
351
|
-
ctx = request["context"]
|
|
352
|
-
|
|
353
|
-
# Always available after successful auth
|
|
354
|
-
user_id = ctx["user_id"] # str: User identifier
|
|
355
|
-
is_staff = ctx["is_staff"] # bool: Staff status
|
|
356
|
-
is_admin = ctx["is_admin"] # bool: Admin status
|
|
357
|
-
backend = ctx["auth_backend"] # str: "jwt", "api_key", etc.
|
|
358
|
-
|
|
359
|
-
# Available if permissions configured
|
|
360
|
-
permissions = ctx.get("permissions", []) # list[str]: Permission strings
|
|
361
|
-
|
|
362
|
-
# Available for JWT auth
|
|
363
|
-
if "auth_claims" in ctx:
|
|
364
|
-
claims = ctx["auth_claims"]
|
|
365
|
-
exp = claims["exp"] # Expiration timestamp
|
|
366
|
-
iat = claims["iat"] # Issued at timestamp
|
|
367
|
-
# Plus any custom claims
|
|
368
|
-
|
|
369
|
-
return {"user_id": user_id, "is_admin": is_admin}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
### Helper Functions
|
|
373
|
-
|
|
374
|
-
```python
|
|
375
|
-
from django_bolt.jwt_utils import (
|
|
376
|
-
get_current_user, # Fetch Django User from DB
|
|
377
|
-
extract_user_id_from_context,
|
|
378
|
-
get_auth_context,
|
|
379
|
-
)
|
|
380
|
-
from django_bolt.params import Depends
|
|
381
|
-
|
|
382
|
-
# Dependency injection to get Django User
|
|
383
|
-
@api.get("/profile")
|
|
384
|
-
async def my_profile(user=Depends(get_current_user)):
|
|
385
|
-
if not user:
|
|
386
|
-
return {"error": "Not authenticated"}
|
|
387
|
-
|
|
388
|
-
return {
|
|
389
|
-
"id": user.id,
|
|
390
|
-
"username": user.username,
|
|
391
|
-
"email": user.email,
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
# Extract just the user ID
|
|
395
|
-
@api.get("/data")
|
|
396
|
-
async def get_data(request):
|
|
397
|
-
user_id = extract_user_id_from_context(request)
|
|
398
|
-
# Use user_id...
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
## Performance Characteristics
|
|
402
|
-
|
|
403
|
-
| Operation | Performance | Notes |
|
|
404
|
-
|-----------|-------------|-------|
|
|
405
|
-
| JWT Validation | ~60k+ RPS | Entirely in Rust, no GIL |
|
|
406
|
-
| API Key Check | ~65k+ RPS | Simple HashSet lookup |
|
|
407
|
-
| Guard Check | ~65k+ RPS | In-memory permission check |
|
|
408
|
-
| Session Auth | ~10-15k RPS | Falls back to Python/Django |
|
|
409
|
-
|
|
410
|
-
**Key Insight**: Authentication/authorization happens in the hot path **before** calling Python handlers, so most invalid requests are rejected at ~60k RPS without ever touching the GIL.
|
|
411
|
-
|
|
412
|
-
## Rust Implementation Details
|
|
413
|
-
|
|
414
|
-
### Key Files
|
|
415
|
-
|
|
416
|
-
- **`src/middleware/auth.rs`**: JWT/API key validation, Claims struct, AuthContext
|
|
417
|
-
- **`src/metadata.rs`**: Parse Python metadata → Rust types at registration
|
|
418
|
-
- **`src/permissions.rs`**: Guard enum and validation logic
|
|
419
|
-
- **`src/lib.rs`**: Request processing pipeline
|
|
420
|
-
|
|
421
|
-
### Performance Optimizations
|
|
422
|
-
|
|
423
|
-
1. **Zero-copy validation**: JWT validation uses `jsonwebtoken` crate directly on request bytes
|
|
424
|
-
2. **No GIL during auth**: Entire auth pipeline runs without acquiring GIL
|
|
425
|
-
3. **Early rejection**: Invalid tokens/permissions rejected before Python handler call
|
|
426
|
-
4. **Metadata compilation**: Auth config parsed once at registration, not per-request
|
|
427
|
-
5. **Efficient data structures**: DashMap for rate limiting, HashSet for permissions
|
|
428
|
-
|
|
429
|
-
## Testing
|
|
430
|
-
|
|
431
|
-
```bash
|
|
432
|
-
# Run auth tests
|
|
433
|
-
uv run pytest python/django_bolt/tests/test_guards_auth.py -v
|
|
434
|
-
uv run pytest python/django_bolt/tests/test_jwt_token.py -v
|
|
435
|
-
|
|
436
|
-
# All tests
|
|
437
|
-
uv run pytest python/django_bolt/tests/ -v
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
## Migration from Old Code
|
|
441
|
-
|
|
442
|
-
If you had direct imports from `django_bolt.auth` or `django_bolt.permissions`, they still work:
|
|
443
|
-
|
|
444
|
-
```python
|
|
445
|
-
# Old imports (still work via backward compat shim)
|
|
446
|
-
from django_bolt.auth import JWTAuthentication
|
|
447
|
-
from django_bolt.permissions import IsAuthenticated
|
|
448
|
-
|
|
449
|
-
# New organized imports (recommended)
|
|
450
|
-
from django_bolt.auth import JWTAuthentication, IsAuthenticated
|
|
451
|
-
# or
|
|
452
|
-
from django_bolt import JWTAuthentication, IsAuthenticated
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
## Examples
|
|
456
|
-
|
|
457
|
-
See `/python/examples/testproject/testproject/api.py` for real-world usage examples.
|
|
458
|
-
|
|
459
|
-
## Benchmarks
|
|
460
|
-
|
|
461
|
-
```bash
|
|
462
|
-
# Run auth-specific benchmarks
|
|
463
|
-
make bench-auth # TODO: Add auth benchmarks to Makefile
|
|
464
|
-
```
|