Skip to content

Commit d036eec

Browse files
authored
Merge pull request #3 from Toruitas/2_4_logging_out
2 4 logging out
2 parents 58f3fe8 + 4184e91 commit d036eec

File tree

29 files changed

+10627
-5
lines changed

29 files changed

+10627
-5
lines changed

.babelrc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"presets": ["@babel/preset-env", "@babel/preset-react"]
3+
}

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Complete JWT Authentication with Django & React
2+
By: Stuart Leitch
3+
4+
This GitHub repo accompanies my tutorial on the subject of how to use JWT Authentication with Django and React.
5+
6+
7+
8+
Requirements:
9+
* Django 2 or 3
10+
* Python 3 only
11+
* React ~16.8

curl-commands.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
curl --header "Content-Type: application/json" -X POST http://127.0.0.1:8000/api/token/obtain/ --data '{"username":"djsr","password":"djsr"}'
2+
curl --header "Content-Type: application/json" -X POST http://127.0.0.1:8000/api/user/create/ --data '{"email":"ichiro@mariners.com","username":"ichiro1","password":"konnichiwa"}'
3+
curl --header "Content-Type: application/json" -X POST http://127.0.0.1:8000/api/token/refresh/ --data '{"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTU4MzMzMDg5MSwianRpIjoiZTZjN2ZjMzMyNzdiNDMwNzgyNGM1MzQyN2U0ZWU2NmYiLCJ1c2VyX2lkIjoxLCJmYXZfY29sb3IiOiJSb3VnZSJ9.acscYBSt57Crm8TAjOkVScjdJ9tPkdeCkr647p6mTqw"}'
4+
curl --header "Content-Type: application/json" --header "Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTYwNDI5MTE2LCJqdGkiOiI1NWVlZDA4MGQ2YTg0MzI4YTZkZTE0Mjg4ZjE3OWE0YyIsInVzZXJfaWQiOjIsImZhdl9jb2xvciI6IiJ9.LXqfhFifGDA6Qg8s4Knl1grPusTLX1lh4YKWuQUuv-k" -X GET http://127.0.0.1:8000/api/hello/

djsr/authentication/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33

44

55
class CustomUser(AbstractUser):
6-
fav_color = models.CharField(blank=True, max_length=120)
6+
fav_color = models.CharField(blank=True, max_length=120)

djsr/authentication/serializers.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# djsr/authentication/serializers.py
2+
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
3+
from rest_framework import serializers
4+
from .models import CustomUser
5+
6+
7+
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
8+
9+
@classmethod
10+
def get_token(cls, user):
11+
token = super(MyTokenObtainPairSerializer, cls).get_token(user)
12+
13+
# Add custom claims
14+
token['fav_color'] = user.fav_color
15+
return token
16+
17+
18+
class CustomUserSerializer(serializers.ModelSerializer):
19+
"""
20+
Currently unused in preference of the below.
21+
"""
22+
email = serializers.EmailField(
23+
required=True
24+
)
25+
username = serializers.CharField(required=True)
26+
password = serializers.CharField(min_length=8, write_only=True, required=True)
27+
28+
class Meta:
29+
model = CustomUser
30+
fields = ('email', 'username', 'password')
31+
extra_kwargs = {'password': {'write_only': True}}
32+
33+
def create(self, validated_data):
34+
password = validated_data.pop('password', None)
35+
instance = self.Meta.model(**validated_data) # as long as the fields are the same, we can just use this
36+
if password is not None:
37+
instance.set_password(password)
38+
instance.save()
39+
return instance
40+

djsr/authentication/urls.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from django.urls import path
2+
from rest_framework_simplejwt import views as jwt_views
3+
from .views import ObtainTokenPairWithColorView, CustomUserCreate, HelloWorldView, LogoutAndBlacklistRefreshTokenForUserView
4+
5+
urlpatterns = [
6+
path('user/create/', CustomUserCreate.as_view(), name="create_user"),
7+
path('token/obtain/', ObtainTokenPairWithColorView.as_view(), name='token_create'),
8+
path('token/refresh/', jwt_views.TokenRefreshView.as_view(), name='token_refresh'),
9+
path('hello/', HelloWorldView.as_view(), name='hello_world'),
10+
path('blacklist/', LogoutAndBlacklistRefreshTokenForUserView.as_view(), name='blacklist')
11+
]

djsr/authentication/views.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,44 @@
1-
from django.shortcuts import render
1+
from rest_framework import status, permissions
2+
from rest_framework.response import Response
3+
from rest_framework_simplejwt.views import TokenObtainPairView
4+
from rest_framework.views import APIView
5+
from rest_framework_simplejwt.tokens import RefreshToken
6+
from .serializers import MyTokenObtainPairSerializer, CustomUserSerializer
27

3-
# Create your views here.
8+
9+
class ObtainTokenPairWithColorView(TokenObtainPairView):
10+
serializer_class = MyTokenObtainPairSerializer
11+
12+
13+
class CustomUserCreate(APIView):
14+
permission_classes = (permissions.AllowAny,)
15+
authentication_classes = ()
16+
17+
def post(self, request, format='json'):
18+
serializer = CustomUserSerializer(data=request.data)
19+
if serializer.is_valid():
20+
user = serializer.save()
21+
if user:
22+
json = serializer.data
23+
return Response(json, status=status.HTTP_201_CREATED)
24+
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
25+
26+
27+
class HelloWorldView(APIView):
28+
29+
def get(self, request):
30+
return Response(data={"hello":"world"}, status=status.HTTP_200_OK)
31+
32+
33+
class LogoutAndBlacklistRefreshTokenForUserView(APIView):
34+
permission_classes = (permissions.AllowAny,)
35+
authentication_classes = ()
36+
37+
def post(self, request):
38+
try:
39+
refresh_token = request.data["refresh_token"]
40+
token = RefreshToken(refresh_token)
41+
token.blacklist()
42+
return Response(status=status.HTTP_205_RESET_CONTENT)
43+
except Exception as e:
44+
return Response(status=status.HTTP_400_BAD_REQUEST)

djsr/djsr/settings.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
"""
1212

1313
import os
14+
from datetime import timedelta
15+
1416

1517
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
1618
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -37,7 +39,10 @@
3739
'django.contrib.sessions',
3840
'django.contrib.messages',
3941
'django.contrib.staticfiles',
40-
'authentication'
42+
'rest_framework_simplejwt.token_blacklist',
43+
'authentication',
44+
'rest_framework',
45+
'frontend'
4146
]
4247

4348
MIDDLEWARE = [
@@ -122,3 +127,28 @@
122127

123128
# Custom user model
124129
AUTH_USER_MODEL = "authentication.CustomUser"
130+
131+
# Rest Framework
132+
REST_FRAMEWORK = {
133+
'DEFAULT_PERMISSION_CLASSES': (
134+
'rest_framework.permissions.IsAuthenticated',
135+
),
136+
'DEFAULT_AUTHENTICATION_CLASSES': (
137+
'rest_framework_simplejwt.authentication.JWTAuthentication',
138+
),
139+
}
140+
141+
SIMPLE_JWT = {
142+
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
143+
'REFRESH_TOKEN_LIFETIME': timedelta(days=14),
144+
'ROTATE_REFRESH_TOKENS': True,
145+
'BLACKLIST_AFTER_ROTATION': True,
146+
'ALGORITHM': 'HS256',
147+
'SIGNING_KEY': SECRET_KEY,
148+
'VERIFYING_KEY': None,
149+
'AUTH_HEADER_TYPES': ('JWT',),
150+
'USER_ID_FIELD': 'id',
151+
'USER_ID_CLAIM': 'user_id',
152+
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
153+
'TOKEN_TYPE_CLAIM': 'token_type',
154+
}

djsr/djsr/urls.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,10 @@
1414
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
1515
"""
1616
from django.contrib import admin
17-
from django.urls import path
17+
from django.urls import path, include
1818

1919
urlpatterns = [
2020
path('admin/', admin.site.urls),
21+
path('api/', include('authentication.urls')),
22+
path('', include('frontend.urls'))
2123
]

djsr/frontend/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)