Реализовано три уровня защиты от доступа владельцев тенантов к /admin/: 1. Явные флаги безопасности в CustomUserManager.create_user() - Добавлены setdefault(is_staff=False, is_superuser=False) - Устраняет зависимость от неявных дефолтов Django 2. Явные флаги при создании владельцев тенантов (tenants/admin.py) - Владельцы создаются с is_staff=False, is_superuser=False - Явная документация намерений в коде 3. Middleware защита на уровне HTTP (TenantAdminAccessMiddleware) - Блокирует доступ к /admin/ на поддоменах тенантов - Только is_superuser=True может войти в админку тенанта - Последний рубеж обороны (defense-in-depth) Дополнительно: - Исправлена видимость alert-уведомлений на странице регистрации (добавлены явные цвета для всех типов alert) Суперпользователи НЕ затронуты: create_superuser() работает как прежде. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
163 lines
4.7 KiB
HTML
163 lines
4.7 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="ru">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{% block title %}Регистрация магазина{% endblock %} - Inventory System</title>
|
|
|
|
<!-- Bootstrap 5 CSS -->
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
|
|
<style>
|
|
body {
|
|
background: linear-gradient(135deg, #1e293b 0%, #334155 100%);
|
|
min-height: 100vh;
|
|
padding: 20px 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
.container {
|
|
max-width: 520px;
|
|
}
|
|
.card {
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
border: none;
|
|
border-radius: 8px;
|
|
overflow: hidden;
|
|
}
|
|
.card-header {
|
|
background: #3b82f6;
|
|
color: white;
|
|
padding: 0.875rem 1.25rem;
|
|
border-bottom: none;
|
|
}
|
|
.card-header h3 {
|
|
font-size: 1.125rem;
|
|
font-weight: 600;
|
|
margin: 0;
|
|
}
|
|
.card-header p {
|
|
font-size: 0.8rem;
|
|
opacity: 0.95;
|
|
margin: 0.2rem 0 0 0;
|
|
}
|
|
.card-body {
|
|
padding: 1.25rem;
|
|
}
|
|
.form-label {
|
|
font-size: 0.875rem;
|
|
font-weight: 500;
|
|
color: #374151;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
.form-control, .input-group-text {
|
|
font-size: 0.9375rem;
|
|
padding: 0.45rem 0.7rem;
|
|
border-radius: 5px;
|
|
}
|
|
.input-group-text {
|
|
background: #f3f4f6;
|
|
border-left: none;
|
|
color: #6b7280;
|
|
font-size: 0.875rem;
|
|
}
|
|
.form-control:focus {
|
|
border-color: #3b82f6;
|
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
}
|
|
.form-text {
|
|
font-size: 0.75rem;
|
|
color: #6b7280;
|
|
margin-top: 0.2rem;
|
|
}
|
|
.text-danger {
|
|
color: #ef4444 !important;
|
|
font-size: 0.8125rem;
|
|
}
|
|
.mb-2 {
|
|
margin-bottom: 0.65rem !important;
|
|
}
|
|
.mb-3 {
|
|
margin-bottom: 0.875rem !important;
|
|
}
|
|
.btn-primary {
|
|
background: #3b82f6;
|
|
border: none;
|
|
font-weight: 500;
|
|
font-size: 0.9rem;
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 6px;
|
|
transition: all 0.2s;
|
|
}
|
|
.btn-primary:hover {
|
|
background: #2563eb;
|
|
transform: translateY(-1px);
|
|
box-shadow: 0 4px 8px rgba(59, 130, 246, 0.3);
|
|
}
|
|
.alert {
|
|
border-radius: 6px;
|
|
font-size: 0.85rem;
|
|
padding: 0.65rem 0.875rem;
|
|
color: #1f2937 !important;
|
|
background-color: #ffffff;
|
|
border: 1px solid rgba(0, 0, 0, 0.1);
|
|
}
|
|
.alert-success {
|
|
background-color: #d1fae5 !important;
|
|
border-color: #10b981 !important;
|
|
color: #065f46 !important;
|
|
}
|
|
.alert-error, .alert-danger {
|
|
background-color: #fee2e2 !important;
|
|
border-color: #ef4444 !important;
|
|
color: #991b1b !important;
|
|
}
|
|
.alert-warning {
|
|
background-color: #fef3c7 !important;
|
|
border-color: #f59e0b !important;
|
|
color: #92400e !important;
|
|
}
|
|
.alert-info {
|
|
background-color: #dbeafe !important;
|
|
border-color: #3b82f6 !important;
|
|
color: #1e40af !important;
|
|
}
|
|
small.text-muted {
|
|
font-size: 0.8125rem;
|
|
color: #6b7280;
|
|
line-height: 1.3;
|
|
}
|
|
.row {
|
|
margin-left: -0.375rem;
|
|
margin-right: -0.375rem;
|
|
}
|
|
.row > * {
|
|
padding-left: 0.375rem;
|
|
padding-right: 0.375rem;
|
|
}
|
|
</style>
|
|
|
|
{% block extra_css %}{% endblock %}
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
{% if messages %}
|
|
<div class="mb-3">
|
|
{% for message in messages %}
|
|
<div class="alert alert-{{ message.tags }} alert-dismissible fade show" role="alert">
|
|
{{ message }}
|
|
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% block content %}{% endblock %}
|
|
</div>
|
|
|
|
<!-- Bootstrap 5 JS -->
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
{% block extra_js %}{% endblock %}
|
|
</body>
|
|
</html>
|