mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-01 21:16:46 +00:00
149 lines
5.2 KiB
Python
149 lines
5.2 KiB
Python
from django.shortcuts import HttpResponseRedirect
|
|
from django.urls import reverse_lazy
|
|
from django.db import connection
|
|
from django.shortcuts import redirect
|
|
import logging
|
|
import time
|
|
import operator
|
|
|
|
from rest_framework.authtoken.models import Token
|
|
|
|
logger = logging.getLogger("inventree")
|
|
|
|
|
|
class AuthRequiredMiddleware(object):
|
|
def __init__(self, get_response):
|
|
self.get_response = get_response
|
|
|
|
def __call__(self, request):
|
|
# Code to be executed for each request before
|
|
# the view (and later middleware) are called.
|
|
|
|
assert hasattr(request, 'user')
|
|
|
|
# API requests are handled by the DRF library
|
|
if request.path_info.startswith('/api/'):
|
|
return self.get_response(request)
|
|
|
|
if not request.user.is_authenticated:
|
|
"""
|
|
Normally, a web-based session would use csrftoken based authentication.
|
|
However when running an external application (e.g. the InvenTree app or Python library),
|
|
we must validate the user token manually.
|
|
"""
|
|
|
|
authorized = False
|
|
|
|
# Allow static files to be accessed without auth
|
|
# Important for e.g. login page
|
|
if request.path_info.startswith('/static/'):
|
|
authorized = True
|
|
|
|
# Unauthorized users can access the login page
|
|
elif request.path_info.startswith('/accounts/'):
|
|
authorized = True
|
|
|
|
elif 'Authorization' in request.headers.keys() or 'authorization' in request.headers.keys():
|
|
auth = request.headers.get('Authorization', request.headers.get('authorization')).strip()
|
|
|
|
if auth.lower().startswith('token') and len(auth.split()) == 2:
|
|
token_key = auth.split()[1]
|
|
|
|
# Does the provided token match a valid user?
|
|
try:
|
|
token = Token.objects.get(key=token_key)
|
|
|
|
# Provide the user information to the request
|
|
request.user = token.user
|
|
authorized = True
|
|
|
|
except Token.DoesNotExist:
|
|
logger.warning(f"Access denied for unknown token {token_key}")
|
|
pass
|
|
|
|
# No authorization was found for the request
|
|
if not authorized:
|
|
# A logout request will redirect the user to the login screen
|
|
if request.path_info == reverse_lazy('logout'):
|
|
return HttpResponseRedirect(reverse_lazy('login'))
|
|
|
|
path = request.path_info
|
|
|
|
# List of URL endpoints we *do not* want to redirect to
|
|
urls = [
|
|
reverse_lazy('login'),
|
|
reverse_lazy('logout'),
|
|
reverse_lazy('admin:login'),
|
|
reverse_lazy('admin:logout'),
|
|
]
|
|
|
|
if path not in urls and not path.startswith('/api/'):
|
|
# Save the 'next' parameter to pass through to the login view
|
|
|
|
return redirect('%s?next=%s' % (reverse_lazy('login'), request.path))
|
|
|
|
response = self.get_response(request)
|
|
|
|
return response
|
|
|
|
|
|
class QueryCountMiddleware(object):
|
|
"""
|
|
This middleware will log the number of queries run
|
|
and the total time taken for each request (with a
|
|
status code of 200). It does not currently support
|
|
multi-db setups.
|
|
|
|
To enable this middleware, set 'log_queries: True' in the local InvenTree config file.
|
|
|
|
Reference: https://www.dabapps.com/blog/logging-sql-queries-django-13/
|
|
|
|
Note: 2020-08-15 - This is no longer used, instead we now rely on the django-debug-toolbar addon
|
|
"""
|
|
|
|
def __init__(self, get_response):
|
|
self.get_response = get_response
|
|
|
|
def __call__(self, request):
|
|
|
|
t_start = time.time()
|
|
response = self.get_response(request)
|
|
t_stop = time.time()
|
|
|
|
if response.status_code == 200:
|
|
total_time = 0
|
|
|
|
if len(connection.queries) > 0:
|
|
|
|
queries = {}
|
|
|
|
for query in connection.queries:
|
|
query_time = query.get('time')
|
|
|
|
sql = query.get('sql').split('.')[0]
|
|
|
|
if sql in queries:
|
|
queries[sql] += 1
|
|
else:
|
|
queries[sql] = 1
|
|
|
|
if query_time is None:
|
|
# django-debug-toolbar monkeypatches the connection
|
|
# cursor wrapper and adds extra information in each
|
|
# item in connection.queries. The query time is stored
|
|
# under the key "duration" rather than "time" and is
|
|
# in milliseconds, not seconds.
|
|
query_time = float(query.get('duration', 0))
|
|
|
|
total_time += float(query_time)
|
|
|
|
logger.debug('{n} queries run, {a:.3f}s / {b:.3f}s'.format(
|
|
n=len(connection.queries),
|
|
a=total_time,
|
|
b=(t_stop - t_start)))
|
|
|
|
for x in sorted(queries.items(), key=operator.itemgetter(1), reverse=True):
|
|
print(x[0], ':', x[1])
|
|
|
|
return response
|