Skip to content

Commit

Permalink
More customisation control in controller schemas (#26)
Browse files Browse the repository at this point in the history
* refactored schema and gave them a more proper name

* Added controller schemas to settings. For more dynamic support

* Added schema_control helper functions and apply schemas to controller

* removed ninja_schema dependency

* removed ninja_schema dependency

* Added some test for custom controller schema

* fixed failing test

* linting

* added doc and some refactoring

* added more test

* check_authentication_fix
  • Loading branch information
eadwinCode committed Mar 17, 2023
1 parent 42c5f44 commit cc79b79
Show file tree
Hide file tree
Showing 17 changed files with 930 additions and 161 deletions.
51 changes: 18 additions & 33 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: 'v4.3.0'
rev: v2.3.0
hooks:
- id: check-merge-conflict
- repo: https://github.com/asottile/yesqa
rev: v1.3.0
hooks:
- id: yesqa
- repo: https://github.com/pycqa/isort
rev: '5.10.1'
- repo: local
hooks:
- id: isort
args: ["--profile", "black"]
- repo: https://github.com/psf/black
rev: '22.6.0'
hooks:
- id: black
language_version: python3 # Should be a command that runs python3.6+
- id: code_formatting
args: []
name: Code Formatting
entry: "make fmt"
types: [python]
language_version: python3.8
language: python
- id: code_linting
args: [ ]
name: Code Linting
entry: "make lint"
types: [ python ]
language_version: python3.8
language: python
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: 'v4.3.0'
rev: v2.3.0
hooks:
- id: end-of-file-fixer
exclude: >-
^docs/[^/]*\.svg$
^examples/[^/]*\.svg$
- id: requirements-txt-fixer
- id: trailing-whitespace
types: [python]
- id: file-contents-sorter
files: |
CONTRIBUTORS.txt|
docs/spelling_wordlist.txt|
.gitignore|
.gitattributes
- id: check-case-conflict
- id: check-json
- id: check-xml
Expand All @@ -43,19 +43,4 @@ repos:
- id: check-added-large-files
- id: check-symlinks
- id: debug-statements
- id: detect-aws-credentials
args: ['--allow-missing-credentials']
- id: detect-private-key
exclude: ^tests/
- repo: https://github.com/asottile/pyupgrade
rev: 'v2.37.1'
hooks:
- id: pyupgrade
args: ['--py37-plus', '--keep-mock']

- repo: https://github.com/Lucas-C/pre-commit-hooks-markup
rev: v1.0.1
hooks:
- id: rst-linter
files: >-
^[^/]+[.]rst$
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ clean: ## Removing cached python compiled files
find . -name __pycache__ | xargs rm -rfv

install: ## Install dependencies
make clean
flit install --deps develop --symlink
pre-commit install -f

lint: ## Run code linters
make clean
Expand All @@ -35,4 +37,8 @@ test-cov: ## Run tests with coverage

doc-deploy: ## Run Deploy Documentation
make clean
mkdocs gh-deploy --force
mkdocs gh-deploy --force

doc-serve: ## Run Deploy Documentation
make clean
mkdocs serve
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ For full documentation, [visit](https://eadwincode.github.io/django-ninja-jwt/).
- Python >= 3.6
- Django >= 2.1
- Django-Ninja >= 0.16.1
- Ninja-Schema >= 0.12.8
- Django-Ninja-Extra >= 0.14.2

## Example
Expand Down
75 changes: 70 additions & 5 deletions docs/customizing_token_claims.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ views, create a subclass for the desired controller as well as a subclass for
its corresponding serializer. Here\'s an example :

!!! info
if you are interested in Asynchronous version of the class, checkout `AsyncNinjaJWTDefaultController` and `AsyncNinjaJWTSlidingController`
if you are interested in Asynchronous version of the class, use `AsyncNinjaJWTDefaultController` and `AsyncNinjaJWTSlidingController`.
Also note, it's only available for Django versions that supports asynchronous actions.

```python
from ninja_jwt.schema import TokenObtainPairSerializer
from ninja_jwt.schema import TokenObtainPairInputSchema
from ninja_jwt.controller import TokenObtainPairController
from ninja_extra import api_controller, route
from ninja_schema import Schema
from ninja import Schema


class UserSchema(Schema):
Expand All @@ -25,12 +26,13 @@ class MyTokenObtainPairOutSchema(Schema):
user: UserSchema


class MyTokenObtainPairSchema(TokenObtainPairSerializer):
class MyTokenObtainPairSchema(TokenObtainPairInputSchema):
def output_schema(self):
out_dict = self.dict(exclude={"password"})
out_dict.update(user=UserSchema.from_orm(self._user))
return MyTokenObtainPairOutSchema(**out_dict)


@api_controller('/token', tags=['Auth'])
class MyTokenObtainPairController(TokenObtainPairController):
@route.post(
Expand All @@ -49,7 +51,6 @@ Here is an example

```python
from ninja import router
from ninja_schema import Schema

router = router('/token')

Expand All @@ -67,3 +68,67 @@ from ninja import NinjaAPI
api = NinjaAPI()
api.add_router('', tags=['Auth'], router=router)
```


### Controller Schema Swapping

You can now swap controller schema in `NINJA_JWT` settings without having to inherit or override Ninja JWT controller function.

All controller input schema must inherit from `ninja_jwt.schema.InputSchemaMixin` and token generating schema should inherit
from `ninja_jwt.schema.TokenObtainInputSchemaBase` or `ninja_jwt.schema.TokenInputSchemaMixin` if you want to have more control.

Using the example above:

```python
# project/schema.py
from typing import Type, Dict
from ninja_jwt.schema import TokenObtainInputSchemaBase
from ninja import Schema
from ninja_jwt.tokens import RefreshToken

class UserSchema(Schema):
first_name: str
email: str


class MyTokenObtainPairOutSchema(Schema):
refresh: str
access: str
user: UserSchema


class MyTokenObtainPairInputSchema(TokenObtainInputSchemaBase):
@classmethod
def get_response_schema(cls) -> Type[Schema]:
return MyTokenObtainPairOutSchema

@classmethod
def get_token(cls, user) -> Dict:
values = {}
refresh = RefreshToken.for_user(user)
values["refresh"] = str(refresh)
values["access"] = str(refresh.access_token)
values.update(user=UserSchema.from_orm(user)) # this will be needed when creating output schema
return values
```

In the `MyTokenObtainPairInputSchema` we override `get_token` to define our token and some data needed for our output schema.
We also override `get_response_schema` to define our output schema `MyTokenObtainPairOutSchema`.

Next, we apply the `MyTokenObtainPairInputSchema` schema to controller. This is simply done in `NINJA_JWT` settings.

```python
# project/settings.py

NINJA_JWT = {
'TOKEN_OBTAIN_PAIR_INPUT_SCHEMA': 'project.schema.MyTokenObtainPairInputSchema',
}
```
Other swappable schemas can be found in [settings](../settings)

![token_customization_git](./img/token_customize.gif)

!!! Note
`Controller Schema Swapping` is only available from **v5.2.4**


21 changes: 15 additions & 6 deletions docs/development_and_contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,26 @@ To do development work for Ninja JWT, make your own fork on Github,
clone it locally, make and activate a virtualenv for it, then from
within the project directory:

``` {.sourceCode .bash}
make install
After that, install flit

```shell
$(venv) pip install flit
```

Install development libraries and pre-commit hooks for code linting and styles

```shell
$(venv) make install
```

To run the tests:

``` {.sourceCode .bash}
make test
```shell
$(venv) make test
```

To run the tests with coverage:

``` {.sourceCode .bash}
make test-cov
```shell
$(venv) make test-cov
```
4 changes: 1 addition & 3 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
- Python >= 3.6
- Django >= 2.1
- Django-Ninja >= 0.16.1
- Ninja-Schema >= 0.12.2
- Django-Ninja-Extra >= 0.11.0

These are the officially supported python and package versions. Other
Expand All @@ -12,7 +11,6 @@ see what is possible.

Installation
============

Ninja JWT can be installed with pip:

pip install django-ninja-jwt
Expand Down Expand Up @@ -112,4 +110,4 @@ extra in the `django-ninja-jwt` requirement:
The `django-ninja-jwt[crypto]` format is recommended in requirements
files in projects using `Ninja JWT`, as a separate `cryptography` requirement
line may later be mistaken for an unused requirement and removed.
[cryptography](https://cryptography.io)
[cryptography](https://cryptography.io)
12 changes: 11 additions & 1 deletion docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ NINJA_JWT = {
'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),

# For Controller Schemas
# FOR OBTAIN PAIR
'TOKEN_OBTAIN_PAIR_INPUT_SCHEMA': "ninja_jwt.schema.TokenObtainPairInputSchema",
'TOKEN_OBTAIN_PAIR_REFRESH_INPUT_SCHEMA': "ninja_jwt.schema.TokenRefreshInputSchema",
# FOR SLIDING TOKEN
'TOKEN_OBTAIN_SLIDING_INPUT_SCHEMA': "ninja_jwt.schema.TokenObtainSlidingInputSchema",
'TOKEN_OBTAIN_SLIDING_REFRESH_INPUT_SCHEMA':"ninja_jwt.schema.TokenRefreshSlidingInputSchema",

'TOKEN_BLACKLIST_INPUT_SCHEMA': "ninja_jwt.schema.TokenBlacklistInputSchema",
'TOKEN_VERIFY_INPUT_SCHEMA': "ninja_jwt.schema.TokenVerifyInputSchema",
}
```

Expand Down Expand Up @@ -247,4 +258,3 @@ More about this in the "Sliding tokens" section below.

The claim name that is used to store the expiration time of a sliding token's
refresh period. More about this in the "Sliding tokens" section below.

7 changes: 6 additions & 1 deletion mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ site_description: Django Ninja JWT - A Simple JWT plugin for Django-Ninja.
site_url: https://eadwincode.github.io/django-ninja-jwt/
repo_name: eadwinCode/django-ninja-jwt
repo_url: https://github.com/eadwinCode/django-ninja-jwt
edit_uri: ''
edit_uri: 'https://github.com/eadwinCode/django-ninja-jwt/docs'

theme:
name: material
Expand Down Expand Up @@ -44,3 +44,8 @@ nav:
- Development and Contributing: development_and_contributing.md
- Experimental Feature: experimental_features.md
#- ninja_jwt package: index.md

markdown_extensions:
- codehilite
- admonition
- pymdownx.superfences
2 changes: 1 addition & 1 deletion ninja_jwt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
"""Django Ninja JWT - JSON Web Token for Django-Ninja"""

__version__ = "5.2.2"
__version__ = "5.2.4"
Loading

0 comments on commit cc79b79

Please sign in to comment.