Refactor: отключена авторизация для отладки (REQUIRE_LOGIN=false), вернуть через REQUIRE_LOGIN=true

Made-with: Cursor
This commit is contained in:
2026-02-26 12:10:42 +00:00
parent 4bfb61d71e
commit 646b3ea3fc
9 changed files with 77 additions and 4 deletions

View File

@@ -17,3 +17,6 @@ DB_PASSWORD=CHANGE_ME_POSTGRES_PASSWORD
# Опционально: дополнительные доверенные источники для CSRF (через запятую) # Опционально: дополнительные доверенные источники для CSRF (через запятую)
# CSRF_TRUSTED_ORIGINS=https://erp.gen7x.ru,https://other.example.com # CSRF_TRUSTED_ORIGINS=https://erp.gen7x.ru,https://other.example.com
# Опционально: требовать вход (по умолчанию false — доступ без авторизации для отладки)
# REQUIRE_LOGIN=true

View File

@@ -1,5 +1,17 @@
# История изменений ERP WaterSurf # История изменений ERP WaterSurf
# История изменений ERP WaterSurf
## 2025-02-25 22:25 UTC Временное отключение авторизации для отладки
**Проблема**: Для быстрой разработки и отладки нужно работать без входа.
**Решение**: Добавлена настройка `REQUIRE_LOGIN` (по умолчанию `false`). При `REQUIRE_LOGIN=false` представления не требуют входа; мидлварь `OptionalAuthMiddleware` подставляет первого активного суперпользователя для анонимных запросов, чтобы меню и поле «Автор» работали. Миксин `config.mixins.LoginRequiredMixin` проверяет `REQUIRE_LOGIN` и при `false` не перенаправляет на логин. Чтобы вернуть авторизацию: в `.env` задать `REQUIRE_LOGIN=true` и перезапустить приложение.
**Изменения**: config/settings.py (REQUIRE_LOGIN, OptionalAuthMiddleware), config/mixins.py, config/middleware.py, documents/views.py, references/views.py, users/views.py (импорт LoginRequiredMixin из config.mixins), .env.example (комментарий про REQUIRE_LOGIN).
---
## 2025-02-25 22:15 UTC Поле «Дата»: размер и кнопка календаря ## 2025-02-25 22:15 UTC Поле «Дата»: размер и кнопка календаря
**Проблема**: Дата не помещалась в поле (обрезка по ширине), кнопка выбора календаря сливалась с тёмным фоном. **Проблема**: Дата не помещалась в поле (обрезка по ширине), кнопка выбора календаря сливалась с тёмным фоном.

View File

@@ -28,11 +28,12 @@ docker compose up -d app
- `SECRET_KEY` — секрет Django (не менее 50 символов) - `SECRET_KEY` — секрет Django (не менее 50 символов)
- `ALLOWED_HOSTS` — через запятую (например `erp.gen7x.ru,localhost`) - `ALLOWED_HOSTS` — через запятую (например `erp.gen7x.ru,localhost`)
- `DEBUG` — true/false - `DEBUG` — true/false
- `REQUIRE_LOGIN` — по умолчанию `false`: доступ без входа (для отладки); `true` — включить авторизацию
## Использование ## Использование
- Веб-интерфейс: после настройки Nginx — https://erp.gen7x.ru/ - Веб-интерфейс: после настройки Nginx — https://erp.gen7x.ru/
- Вход по логину/паролю (пользователи Django). - Вход по логину/паролю (пользователи Django). При `REQUIRE_LOGIN=false` доступ без входа (для отладки).
- Меню: Справочники (валюты, виды заказов, клиенты, организации, поставщики, сотрудники, счета, товары), Документы (заказы клиентов, заказы поставщику, поступления, перемещения, расходы). - Меню: Справочники (валюты, виды заказов, клиенты, организации, поставщики, сотрудники, счета, товары), Документы (заказы клиентов, заказы поставщику, поступления, перемещения, расходы).
- Поле «Автор» в документах подставляется из профиля пользователя (связь User → Сотрудник в разделе «Пользователи» / админка). - Поле «Автор» в документах подставляется из профиля пользователя (связь User → Сотрудник в разделе «Пользователи» / админка).

33
app/config/middleware.py Normal file
View File

@@ -0,0 +1,33 @@
"""
Мидлварь: при отключённой авторизации (REQUIRE_LOGIN=False) подставляет
суперпользователя для анонимных запросов, чтобы меню и поле «Автор» работали.
"""
from django.conf import settings
from django.contrib.auth import get_user_model
_user_model = get_user_model()
_cached_dev_user = None
def get_dev_user():
global _cached_dev_user
if _cached_dev_user is None:
_cached_dev_user = _user_model.objects.filter(is_superuser=True, is_active=True).first()
return _cached_dev_user
class OptionalAuthMiddleware:
"""
Если REQUIRE_LOGIN=False и пользователь не аутентифицирован,
подставить первого активного суперпользователя (для отладки).
"""
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
if not getattr(settings, "REQUIRE_LOGIN", True) and not request.user.is_authenticated:
user = get_dev_user()
if user:
request.user = user
return self.get_response(request)

19
app/config/mixins.py Normal file
View File

@@ -0,0 +1,19 @@
"""
Миксины для представлений.
LoginRequiredMixin при REQUIRE_LOGIN=False не требует входа (для отладки/разработки).
"""
from django.contrib.auth.mixins import LoginRequiredMixin as BaseLoginRequiredMixin
from django.conf import settings
class LoginRequiredMixin(BaseLoginRequiredMixin):
"""
Требует вход только если в настройках включено REQUIRE_LOGIN.
При REQUIRE_LOGIN=False доступ без авторизации (для отладки).
Чтобы вернуть авторизацию: REQUIRE_LOGIN=true в .env или в settings.
"""
def dispatch(self, request, *args, **kwargs):
if getattr(settings, "REQUIRE_LOGIN", True):
return super().dispatch(request, *args, **kwargs)
return super(BaseLoginRequiredMixin, self).dispatch(request, *args, **kwargs)

View File

@@ -38,6 +38,7 @@ MIDDLEWARE = [
"django.middleware.common.CommonMiddleware", "django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware", "django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware",
"config.middleware.OptionalAuthMiddleware",
"django.contrib.messages.middleware.MessageMiddleware", "django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware", "django.middleware.clickjacking.XFrameOptionsMiddleware",
"django.middleware.locale.LocaleMiddleware", "django.middleware.locale.LocaleMiddleware",
@@ -95,6 +96,10 @@ LOGIN_URL = "users:login"
LOGIN_REDIRECT_URL = "users:home" LOGIN_REDIRECT_URL = "users:home"
LOGOUT_REDIRECT_URL = "users:login" LOGOUT_REDIRECT_URL = "users:login"
# Отладка/разработка: REQUIRE_LOGIN=false — доступ без входа (мидлварь подставит суперпользователя).
# Чтобы вернуть авторизацию: REQUIRE_LOGIN=true в .env.
REQUIRE_LOGIN = os.environ.get("REQUIRE_LOGIN", "false").lower() in ("1", "true", "yes")
# Логирование # Логирование
LOGGING = { LOGGING = {
"version": 1, "version": 1,

View File

@@ -1,7 +1,7 @@
"""Представления документов: списки и формы создания/редактирования.""" """Представления документов: списки и формы создания/редактирования."""
import logging import logging
from django.views.generic import ListView, CreateView, UpdateView, DeleteView, DetailView from django.views.generic import ListView, CreateView, UpdateView, DeleteView, DetailView
from django.contrib.auth.mixins import LoginRequiredMixin from config.mixins import LoginRequiredMixin
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.shortcuts import redirect, get_object_or_404 from django.shortcuts import redirect, get_object_or_404
from django.contrib import messages from django.contrib import messages

View File

@@ -3,7 +3,7 @@ CRUD для справочников (списки и формы).
""" """
import logging import logging
from django.views.generic import ListView, CreateView, UpdateView, DeleteView from django.views.generic import ListView, CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin from config.mixins import LoginRequiredMixin
from django.urls import reverse_lazy from django.urls import reverse_lazy
from django.contrib import messages from django.contrib import messages
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _

View File

@@ -4,7 +4,7 @@
import logging import logging
from django.contrib.auth.views import LoginView, LogoutView from django.contrib.auth.views import LoginView, LogoutView
from django.views.generic import TemplateView from django.views.generic import TemplateView
from django.contrib.auth.mixins import LoginRequiredMixin from config.mixins import LoginRequiredMixin
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)