[PUI] Logout Fixes (#6318)

* Refactor method to extract token from request

* Reimplement error-report API endpoint

- Removed in previous commit - b8b3dfc90e
- Adds unit tests to ensure it doesn't happen again

* Adds custom logout view for API

- Ensure correct token gets deleted
- Our new custom token setup is incompatible with default dj-rest-auth
This commit is contained in:
Oliver 2024-01-22 23:07:35 +11:00 committed by GitHub
parent e7d926f983
commit ab921ccb31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 49 additions and 25 deletions

View File

@ -18,6 +18,23 @@ from users.models import ApiToken
logger = logging.getLogger('inventree')
def get_token_from_request(request):
"""Extract token information from a request object."""
auth_keys = ['Authorization', 'authorization']
token = None
for k in auth_keys:
if auth_header := request.headers.get(k, None):
auth_header = auth_header.strip().lower().split()
if len(auth_header) > 1 and auth_header[0].startswith('token'):
token = auth_header[1]
break
return token
class AuthRequiredMiddleware(object):
"""Check for user to be authenticated."""
@ -25,28 +42,9 @@ class AuthRequiredMiddleware(object):
"""Save response object."""
self.get_response = get_response
def get_auth_headers(self, request):
"""Extract authorization headers from request."""
keys = ['Authorization', 'authorization']
for k in keys:
if k in request.headers.keys():
return request.headers[k]
return None
def check_token(self, request) -> bool:
"""Check if the user is authenticated via token."""
auth = self.get_auth_headers(request)
if not auth:
return False
auth = auth.strip().lower().split()
if len(auth) > 1 and auth[0].startswith('token'):
token = auth[1]
if token := get_token_from_request(request):
# Does the provided token match a valid user?
try:
token = ApiToken.objects.get(key=token)

View File

@ -148,6 +148,7 @@ apipatterns = [
SocialAccountDisconnectView.as_view(),
name='social_account_disconnect',
),
path('logout/', users.api.Logout.as_view(), name='api-logout'),
path('', include('dj_rest_auth.urls')),
]),
),

View File

@ -7,6 +7,7 @@ from django.contrib.auth import get_user, login
from django.contrib.auth.models import Group, User
from django.urls import include, path, re_path
from dj_rest_auth.views import LogoutView
from rest_framework import exceptions, permissions
from rest_framework.response import Response
from rest_framework.views import APIView
@ -200,6 +201,29 @@ class GroupList(ListCreateAPI):
ordering_fields = ['name']
class Logout(LogoutView):
"""API view for logging out via API."""
def logout(self, request):
"""Logout the current user.
Deletes user token associated with request.
"""
from InvenTree.middleware import get_token_from_request
if request.user:
token_key = get_token_from_request(request)
if token_key:
try:
token = ApiToken.objects.get(key=token_key, user=request.user)
token.delete()
except ApiToken.DoesNotExist:
pass
return super().logout(request)
class GetAuthToken(APIView):
"""Return authentication token for an authenticated user."""

View File

@ -48,16 +48,17 @@ export const doClassicLogin = async (username: string, password: string) => {
* Logout the user (invalidate auth token)
*/
export const doClassicLogout = async () => {
// Set token in context
const { setToken } = useSessionState.getState();
setToken(undefined);
// Logout from the server session
await api.post(apiUrl(ApiPaths.user_logout));
// Set token in context
const { setToken } = useSessionState.getState();
setToken(undefined);
notifications.show({
title: t`Logout successful`,
message: t`See you soon.`,
message: t`You have been logged out`,
color: 'green',
icon: <IconCheck size="1rem" />
});