Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Andrew-Chen-Wang committed Jul 9, 2020
0 parents commit 4470aea
Show file tree
Hide file tree
Showing 20 changed files with 547 additions and 0 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2020 SimpleJWT

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
64 changes: 64 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Template Repository for DRF SimpleJWT Apps

Initially created: 3 July 2020

TL;DR: Django server repository setup for SimpleJWT. Test user: `test` and pw `test`.

---
### Example repositories

- Android: [Andrew-Chen-Wang/mobile-auth-example](https://github.com/Andrew-Chen-Wang/mobile-auth-example)
- iOS: [Andrew-Chen-Wang/mobile-auth-example](https://github.com/Andrew-Chen-Wang/mobile-auth-example)

---
### Introduction

This template repository is dedicated to generating
a Django + DRF server with SimpleJWT already setup.
The purpose of this is to easily create repositories
that demonstrate clear usage of SimpleJWT.

If you're not using a frontend framework like React
or some kind of mobile device not using a web browser,
then please use session authentication. I.e. if you're
using plain HTML with Jinja 2 template tags, use the
built-in session authentication middlewear as that
is proven to be the safest and thus far never broken
method of secure authentication.

Note: this template repository is adopted from
[Andrew-Chen-Wang/mobile-auth-example](https://github.com/Andrew-Chen-Wang/mobile-auth-example)
for Android and iOS usage. The license is Apache 2.0
for that example repository.

---
### Usage

1. To generate a repository using this template,
press "Use this template" (highlighted in green).
Note, this will NOT create a fork of the repository.
2. Create your git repository, connect via the ssh remote, and pull.
3. `cd server` to get your terminal/cmd into the server directory.
4. To run the server, create a virtual environment `virtualenv venv && source venv/bin/activate`, install packages `pip install -r requirements.txt` -- the requirements.txt file is inside the server subdirectory -- and do `python manage.py migrate && python manage.py runserver`.
- Again, make sure when you do this, you are inside the server directory on your terminal/cmd.
- On Windows, you should do `venv\Scripts\activate` instead of `source venv/bin/activate`
5. If you're writing for an example repository, please create
a new directory labeled with the name of the framework (e.g. jwt-ios),
and add its `.gitignore`. Please use the
[github/gitignore](https://github.com/github/gitignore) repository.
Provide detailed instructions if necessary.

A default user with the username `test` and password `test` have been created.

This repository does not come with throttling, but **it is
highly recommended that you add throttling to your entire
project.** You can use a third-party package called
Django-ratelimit or DRF's internal throttling mechanism.
Django-ratelimit is more extensive -- covering Django views,
as well -- and thus more supported by SimpleJWT.

---
### License

This repository is licensed under the
[MIT License](https://github.com/SimpleJWT/drf-SimpleJWT-server-template/blob/master/LICENSE).
124 changes: 124 additions & 0 deletions server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/
20 changes: 20 additions & 0 deletions server/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Django Server

The backend works by using Django, Django Rest Framework, and DRF SimpleJWT.

For this demonstration, SimpleJWT utilizes the refresh and access token methodology. The client sends its credentials to the server once and receives an access and refresh token. Everytime you want to do authentication on a view, the client will send the access token; however, that access token expires (in our case, in 5 minutes for security reasons). Once it expires, instead of resending the credentials, we use the refresh token to get a new access token.

If the refresh token expires (after 1 day for security reasons), the client needs to send the username and password again.

### Running the server

1. Create a virtual environment and install the packages: `virtualenv venv && source venv/bin/activate && pip install -r requirements.txt`.
- Again, make sure when you do this, you are inside the server directory on your terminal/cmd.
- On Windows, you should do `venv\Scripts\activate` instead of `source venv/bin/activate`
2. Run the server: `python manage.py migrate && python manage.py runserver`

A default user with the username `test` and password `test` have been created.

### Other suggestions

I also suggest you use a rate limiter, either provided by Django Rest Framework or a more sophisticated one like django-ratelimit so that you can rate limit across your entire application, not just your REST API.
21 changes: 21 additions & 0 deletions server/manage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)


if __name__ == '__main__':
main()
Empty file added server/public/__init__.py
Empty file.
3 changes: 3 additions & 0 deletions server/public/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.contrib import admin

# Register your models here.
5 changes: 5 additions & 0 deletions server/public/apps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.apps import AppConfig


class PublicConfig(AppConfig):
name = 'public'
18 changes: 18 additions & 0 deletions server/public/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 3.0.3 on 2020-03-02 21:13

from django.db import migrations
from django.contrib.auth.models import User


def create_user(apps, schema_editor):
User.objects.create_superuser("test", password="test")


class Migration(migrations.Migration):

dependencies = [
]

operations = [
migrations.RunPython(create_user)
]
Empty file.
3 changes: 3 additions & 0 deletions server/public/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.db import models

# Create your models here.
3 changes: 3 additions & 0 deletions server/public/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from django.test import TestCase

# Create your tests here.
19 changes: 19 additions & 0 deletions server/public/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from django.urls import path, include
from . import views
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

from rest_framework import routers
router = routers.DefaultRouter()
router.register('ping', views.PingViewSet, basename="ping")

urlpatterns = [
path('api/token/access/', TokenRefreshView.as_view(), name='token_get_access'),
path('api/token/both/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/', include(router.urls))
]

"""
- For the first view, you send the refresh token to get a new access token.
- For the second view, you send the client credentials (username and password)
to get BOTH a new access and refresh token.
"""
21 changes: 21 additions & 0 deletions server/public/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK
from rest_framework.permissions import IsAuthenticated


class PingViewSet(GenericViewSet, ListModelMixin):
"""
Helpful class for internal health checks
for when your server deploys. Typical of AWS
applications behind ALB which does default 30
second ping/health checks.
"""
permission_classes = [IsAuthenticated]

def list(self, request, *args, **kwargs):
return Response(
data={"id": request.GET.get("id")},
status=HTTP_200_OK
)
7 changes: 7 additions & 0 deletions server/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
asgiref==3.2.3
Django==3.0.7
djangorestframework==3.11.0
djangorestframework-simplejwt==4.4.0
PyJWT==1.7.1
pytz==2019.3
sqlparse==0.3.1
Empty file added server/server/__init__.py
Empty file.
16 changes: 16 additions & 0 deletions server/server/asgi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
ASGI config for server project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/3.0/howto/deployment/asgi/
"""

import os

from django.core.asgi import get_asgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'server.settings')

application = get_asgi_application()
Loading

0 comments on commit 4470aea

Please sign in to comment.