mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 05:05:42 +00:00 
			
		
		
		
	[PUI] Session authentication (#6970)
* Adjust backend cookie settings * Allow CORS requests to /accounts/ * Refactor frontend code - Remove API token functions - Simplify cookie approach - Add isLoggedIn method * Adjust REST_AUTH settings * Cleanup auth functions in auth.tsx * Adjust CSRF_COOKIE_SAMESITE value * Fix login request * Prevent session auth on login view - Existing (invalid) session token causes 403 * Refactor ApiImage - Point to the right host - Simplify code - Now we use session cookies, so it *Just Works* * Fix download for attachment table - Now works with remote host * Cleanup settings.py * Refactor login / logout notifications * Update API version * Update src/frontend/src/components/items/AttachmentLink.tsx Co-authored-by: Lukas <76838159+wolflu05@users.noreply.github.com> * fix assert url * Remove comment * Add explicit page to logout user * Change tests to first logout * Prune dead code * Adjust tests * Cleanup * Direct to login view * Trying something * Update CUI test * Fix basic tests * Refactoring * Fix basic checks * Fix for PUI command tests * More test updates * Add speciifc test for quick login * More cleanup of playwright tests * Add some missing icons * Fix typo * Ignore coverage report for playwright test * Remove coveralls upload task --------- Co-authored-by: Lukas <76838159+wolflu05@users.noreply.github.com> Co-authored-by: Matthias Mair <code@mjmair.com>
This commit is contained in:
		| @@ -1,12 +1,16 @@ | ||||
| """InvenTree API version information.""" | ||||
|  | ||||
| # InvenTree API version | ||||
| INVENTREE_API_VERSION = 187 | ||||
| INVENTREE_API_VERSION = 188 | ||||
| """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" | ||||
|  | ||||
| INVENTREE_API_TEXT = """ | ||||
|  | ||||
| v187 - 2024-03-10 : https://github.com/inventree/InvenTree/pull/6985 | ||||
| v188 - 2024-04-16 : https://github.com/inventree/InvenTree/pull/6970 | ||||
|     - Adds session authentication support for the API | ||||
|     - Improvements for login / logout endpoints for better support of React web interface | ||||
|  | ||||
| v187 - 2024-04-10 : https://github.com/inventree/InvenTree/pull/6985 | ||||
|     - Allow Part list endpoint to be sorted by pricing_min and pricing_max values | ||||
|     - Allow BomItem list endpoint to be sorted by pricing_min and pricing_max values | ||||
|     - Allow InternalPrice and SalePrice endpoints to be sorted by quantity | ||||
|   | ||||
| @@ -492,10 +492,18 @@ if DEBUG: | ||||
|         'rest_framework.renderers.BrowsableAPIRenderer' | ||||
|     ) | ||||
|  | ||||
| # dj-rest-auth | ||||
| # JWT switch | ||||
| USE_JWT = get_boolean_setting('INVENTREE_USE_JWT', 'use_jwt', False) | ||||
| REST_USE_JWT = USE_JWT | ||||
|  | ||||
| # dj-rest-auth | ||||
| REST_AUTH = { | ||||
|     'SESSION_LOGIN': True, | ||||
|     'TOKEN_MODEL': 'users.models.ApiToken', | ||||
|     'TOKEN_CREATOR': 'users.models.default_create_token', | ||||
|     'USE_JWT': USE_JWT, | ||||
| } | ||||
|  | ||||
| OLD_PASSWORD_FIELD_ENABLED = True | ||||
| REST_AUTH_REGISTER_SERIALIZERS = { | ||||
|     'REGISTER_SERIALIZER': 'InvenTree.forms.CustomRegisterSerializer' | ||||
| @@ -510,6 +518,7 @@ if USE_JWT: | ||||
|     ) | ||||
|     INSTALLED_APPS.append('rest_framework_simplejwt') | ||||
|  | ||||
|  | ||||
| # WSGI default setting | ||||
| WSGI_APPLICATION = 'InvenTree.wsgi.application' | ||||
|  | ||||
| @@ -1092,6 +1101,13 @@ if not TESTING and len(CSRF_TRUSTED_ORIGINS) == 0: | ||||
|         ) | ||||
|         sys.exit(-1) | ||||
|  | ||||
| # Additional CSRF settings | ||||
| CSRF_HEADER_NAME = 'HTTP_X_CSRFTOKEN' | ||||
| CSRF_COOKIE_NAME = 'csrftoken' | ||||
| CSRF_COOKIE_SAMESITE = 'Lax' | ||||
| SESSION_COOKIE_SECURE = True | ||||
| SESSION_COOKIE_SAMESITE = 'Lax' | ||||
|  | ||||
| USE_X_FORWARDED_HOST = get_boolean_setting( | ||||
|     'INVENTREE_USE_X_FORWARDED_HOST', | ||||
|     config_key='use_x_forwarded_host', | ||||
|   | ||||
| @@ -160,6 +160,7 @@ apipatterns = [ | ||||
|                 SocialAccountDisconnectView.as_view(), | ||||
|                 name='social_account_disconnect', | ||||
|             ), | ||||
|             path('login/', users.api.Login.as_view(), name='api-login'), | ||||
|             path('logout/', users.api.Logout.as_view(), name='api-logout'), | ||||
|             path( | ||||
|                 'login-redirect/', | ||||
|   | ||||
| @@ -8,9 +8,11 @@ from django.contrib.auth.models import Group, User | ||||
| from django.urls import include, path, re_path | ||||
| from django.views.generic.base import RedirectView | ||||
|  | ||||
| from dj_rest_auth.views import LogoutView | ||||
| from dj_rest_auth.views import LoginView, LogoutView | ||||
| from drf_spectacular.utils import OpenApiResponse, extend_schema, extend_schema_view | ||||
| from rest_framework import exceptions, permissions | ||||
| from rest_framework.authentication import BasicAuthentication | ||||
| from rest_framework.decorators import authentication_classes | ||||
| from rest_framework.response import Response | ||||
| from rest_framework.views import APIView | ||||
|  | ||||
| @@ -205,6 +207,18 @@ class GroupList(ListCreateAPI): | ||||
|     ordering_fields = ['name'] | ||||
|  | ||||
|  | ||||
| @authentication_classes([BasicAuthentication]) | ||||
| @extend_schema_view( | ||||
|     post=extend_schema( | ||||
|         responses={200: OpenApiResponse(description='User successfully logged in')} | ||||
|     ) | ||||
| ) | ||||
| class Login(LoginView): | ||||
|     """API view for logging in via API.""" | ||||
|  | ||||
|     ... | ||||
|  | ||||
|  | ||||
| @extend_schema_view( | ||||
|     post=extend_schema( | ||||
|         responses={200: OpenApiResponse(description='User successfully logged out')} | ||||
|   | ||||
| @@ -56,6 +56,17 @@ def default_token_expiry(): | ||||
|     return InvenTree.helpers.current_date() + datetime.timedelta(days=365) | ||||
|  | ||||
|  | ||||
| def default_create_token(token_model, user, serializer): | ||||
|     """Generate a default value for the token.""" | ||||
|     token = token_model.objects.filter(user=user, name='', revoked=False) | ||||
|  | ||||
|     if token.exists(): | ||||
|         return token.first() | ||||
|  | ||||
|     else: | ||||
|         return token_model.objects.create(user=user, name='') | ||||
|  | ||||
|  | ||||
| class ApiToken(AuthToken, InvenTree.models.MetadataMixin): | ||||
|     """Extends the default token model provided by djangorestframework.authtoken. | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user