-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feature(add jwt authentication): return jwt token when user logs in
-update user serializer -update user model -update user renderer -configure JWT on backends.py [finishes #164047057]
- Loading branch information
Swaleh Matongwa
authored and
Swaleh Matongwa
committed
Mar 4, 2019
1 parent
fbcfd60
commit b360e41
Showing
10 changed files
with
213 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,74 @@ | ||
# import jwt | ||
# | ||
# from django.conf import settings | ||
# | ||
# from rest_framework import authentication, exceptions | ||
# | ||
# from .models import User | ||
import jwt | ||
import datetime | ||
from django.conf import settings | ||
|
||
from rest_framework import authentication, exceptions | ||
|
||
from .models import User | ||
|
||
"""Configure JWT Here""" | ||
|
||
|
||
class JWTAuthentication(authentication.BaseAuthentication): | ||
authentication_header_prefix = 'Token' | ||
|
||
def authenticate(self, request): | ||
""" | ||
The `authenticate` method is called on every request regardless of | ||
whether the endpoint requires authentication. | ||
""" | ||
request.user = None | ||
|
||
auth_header = authentication.get_authorization_header(request).split() | ||
auth_header_prefix = self.authentication_header_prefix.lower() | ||
|
||
if not auth_header: | ||
return None | ||
|
||
if len(auth_header) == 1: | ||
# Invalid token header. No credentials provided. Do not attempt to | ||
# authenticate. | ||
return None | ||
|
||
elif len(auth_header) > 2: | ||
# Invalid token header. The Token string should not contain spaces. Do | ||
# not attempt to authenticate. | ||
return None | ||
|
||
# The JWT library we're using can't handle the `byte` type, which is | ||
# commonly used by standard libraries in Python 3. To get around this, | ||
# we simply have to decode `prefix` and `token`. This does not make for | ||
# clean code, but it is a good decision because we would get an error | ||
# if we didn't decode these values. | ||
prefix = auth_header[0].decode('utf-8') | ||
token = auth_header[1].decode('utf-8') | ||
|
||
if prefix.lower() != auth_header_prefix: | ||
# The auth header prefix is not what we expected. Do not attempt to | ||
# authenticate. | ||
return None | ||
|
||
return self._authenticate_credentials(request, token) | ||
|
||
def _authenticate_credentials(self, request, token): | ||
""" | ||
Try to authenticate the given credentials. If authentication is | ||
successful, return the user and token. If not, throw an error. | ||
""" | ||
try: | ||
payload = jwt.decode(token, settings.SECRET_KEY) | ||
except: | ||
msg = 'Invalid authentication. Could not decode token.' | ||
raise exceptions.AuthenticationFailed(msg) | ||
|
||
try: | ||
user = User.objects.get(pk=payload['id']) | ||
except User.DoesNotExist: | ||
msg = 'No user matching this token was found.' | ||
raise exceptions.AuthenticationFailed(msg) | ||
|
||
if not user.is_active: | ||
msg = 'This user has been deactivated.' | ||
raise exceptions.AuthenticationFailed(msg) | ||
|
||
return (user, token) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
authors/apps/authentication/tests/test_jwt_authentication.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
"""Test JWT authentication""" | ||
import json | ||
from rest_framework.test import APITestCase, APIClient | ||
from rest_framework.views import status | ||
|
||
# tests for Endpoints | ||
|
||
|
||
class UserTest(APITestCase): | ||
client = APIClient() | ||
|
||
def setUp(self): | ||
# add test data | ||
self.user = { | ||
"user": { | ||
"email": "caro@yahoo.com", | ||
"username": "caro", | ||
"password": "07921513542" | ||
} | ||
} | ||
|
||
self.headers = {"Authorization": ""} | ||
|
||
def test_login_user_JWT_genaration(self): | ||
""" | ||
test login | ||
""" | ||
# create user | ||
response = self.client.post('/api/users/', self.user, format='json') | ||
# hit the API endpoint | ||
response = self.client.post( | ||
'/api/users/login/', self.user, format='json') | ||
result = json.loads(response.content) | ||
|
||
self.assertIn('token', str(result)) | ||
self.assertEqual(response.status_code, status.HTTP_200_OK) | ||
|
||
def test_retrieve_user_with_JWT(self): | ||
""" | ||
test retrieve user with JWT | ||
""" | ||
# create user | ||
response = self.client.post('/api/users/', self.user, format='json') | ||
# Login user | ||
response = self.client.post( | ||
'/api/users/login/', self.user, format='json') | ||
result = json.loads(response.content) | ||
self.client.credentials( | ||
HTTP_AUTHORIZATION='Token ' + result["user"]["token"]) | ||
|
||
# Retrieve user | ||
response = self.client.get('/api/user/', self.user, format='json') | ||
result = json.loads(response.content) | ||
self.assertEqual(result["user"]["email"], "caro@yahoo.com") | ||
self.assertEqual(response.status_code, status.HTTP_200_OK) |
Oops, something went wrong.