Skip to content

Commit c3cf369

Browse files
committed
2-4 concluded
1 parent d6d2472 commit c3cf369

File tree

7 files changed

+52
-11
lines changed

7 files changed

+52
-11
lines changed

djsr/authentication/urls.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from django.urls import path
22
from rest_framework_simplejwt import views as jwt_views
3-
from .views import ObtainTokenPairWithColorView, CustomUserCreate, HelloWorldView
3+
from .views import ObtainTokenPairWithColorView, CustomUserCreate, HelloWorldView, LogoutAndBlacklistRefreshTokenForUserView
44

55
urlpatterns = [
66
path('user/create/', CustomUserCreate.as_view(), name="create_user"),
77
path('token/obtain/', ObtainTokenPairWithColorView.as_view(), name='token_create'),
88
path('token/refresh/', jwt_views.TokenRefreshView.as_view(), name='token_refresh'),
9-
path('hello/', HelloWorldView.as_view(), name='hello_world')
9+
path('hello/', HelloWorldView.as_view(), name='hello_world'),
10+
path('blacklist/', LogoutAndBlacklistRefreshTokenForUserView.as_view(), name='blacklist')
1011
]

djsr/authentication/views.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from rest_framework.response import Response
33
from rest_framework_simplejwt.views import TokenObtainPairView
44
from rest_framework.views import APIView
5+
from rest_framework_simplejwt.tokens import RefreshToken
56

67
from .serializers import MyTokenObtainPairSerializer, CustomUserSerializer
78

@@ -28,3 +29,15 @@ class HelloWorldView(APIView):
2829

2930
def get(self, request):
3031
return Response(data={"hello":"world"}, status=status.HTTP_200_OK)
32+
33+
34+
class LogoutAndBlacklistRefreshTokenForUserView(APIView):
35+
36+
def post(self, request):
37+
try:
38+
refresh_token = request.data["refresh_token"]
39+
token = RefreshToken(refresh_token)
40+
token.blacklist()
41+
return Response(status=status.HTTP_205_RESET_CONTENT)
42+
except Exception as e:
43+
return Response(status=status.HTTP_400_BAD_REQUEST)

djsr/djsr/settings.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
'django.contrib.sessions',
4040
'django.contrib.messages',
4141
'django.contrib.staticfiles',
42+
'rest_framework_simplejwt.token_blacklist',
4243
'authentication',
4344
'rest_framework',
4445
'frontend'
@@ -141,7 +142,7 @@
141142
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
142143
'REFRESH_TOKEN_LIFETIME': timedelta(days=14),
143144
'ROTATE_REFRESH_TOKENS': True,
144-
'BLACKLIST_AFTER_ROTATION': False,
145+
'BLACKLIST_AFTER_ROTATION': True,
145146
'ALGORITHM': 'HS256',
146147
'SIGNING_KEY': SECRET_KEY,
147148
'VERIFYING_KEY': None,

djsr/frontend/src/axiosApi.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const axiosInstance = axios.create({
66
baseURL: 'http://127.0.0.1:8000/api/',
77
timeout: 5000,
88
headers: {
9-
'Authorization': "JWT " + localStorage.getItem('access_token'),
9+
'Authorization': localStorage.getItem('access_token') ? "JWT " + localStorage.getItem('access_token') : null,
1010
'Content-Type': 'application/json',
1111
'accept': 'application/json'
1212
}
@@ -17,7 +17,8 @@ axiosInstance.interceptors.response.use(
1717
error => {
1818
const originalRequest = error.config;
1919

20-
if (error.response.status === 401 && error.response.statusText === "Unauthorized") {
20+
// test for token presence, no point in sending a request if token isn't present
21+
if (localStorage.getItem('refresh_token') && error.response.status === 401 && error.response.statusText === "Unauthorized") {
2122
const refresh_token = localStorage.getItem('refresh_token');
2223

2324
return axiosInstance

djsr/frontend/src/components/App.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,31 @@ import Login from "./login";
44
import Signup from "./signup";
55
import Hello from "./hello";
66

7+
import axiosInstance from "../axiosApi";
8+
9+
710
class App extends Component {
11+
12+
constructor() {
13+
super();
14+
this.handleLogout = this.handleLogout.bind(this);
15+
}
16+
17+
async handleLogout() {
18+
try {
19+
const response = await axiosInstance.post('/blacklist/', {
20+
"refresh_token": localStorage.getItem("refresh_token")
21+
});
22+
localStorage.removeItem('access_token');
23+
localStorage.removeItem('refresh_token');
24+
axiosInstance.defaults.headers['Authorization'] = null;
25+
return response;
26+
}
27+
catch (e) {
28+
console.log(e);
29+
}
30+
};
31+
832
render() {
933
return (
1034
<div className="site">
@@ -13,6 +37,7 @@ class App extends Component {
1337
<Link className={"nav-link"} to={"/login/"}>Login</Link>
1438
<Link className={"nav-link"} to={"/signup/"}>Signup</Link>
1539
<Link className={"nav-link"} to={"/hello/"}>Hello</Link>
40+
<button onClick={this.handleLogout}>Logout</button>
1641
</nav>
1742
<main>
1843
<h1>Ahhh after 10,000 years I'm free. Time to conquer the Earth!</h1>

djsr/frontend/src/components/hello.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ class Hello extends Component {
2020
});
2121
return message;
2222
}catch(error){
23-
console.log("Error: ", JSON.stringify(error, null, 4));
24-
throw error;
23+
console.log("Hello error: ", JSON.stringify(error, null, 4));
24+
// throw error; todo
2525
}
2626
}
2727

djsr/frontend/static/frontend/public/main.js

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)