feat(auth): enhance user authentication system
- Implemented custom login and logout views replacing the default Django auth views to provide a more tailored user experience. - Enforced login requirements for main user area and content views, ensuring that only authenticated users can access specific pages. - Updated the base template to dynamically display user authentication status, enhancing the user interface by showing whether a user is logged in and their email. - Added settings for login, logout, and post-login redirect URLs, utilizing reverse_lazy for URL resolution, improving maintainability and readability of URL management. - Created a new login template that includes form handling and error display to support the custom login view. These changes create a more secure and user-friendly authentication flow, reflecting a commitment to both security and user experience improvements.
This commit is contained in:
parent
6ba838f770
commit
c9e9e99728
5 changed files with 70 additions and 10 deletions
|
@ -3,6 +3,8 @@ from autosecretkey import AutoSecretKey
|
|||
from pathlib import Path
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from django.urls import reverse_lazy
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
|
||||
|
@ -241,3 +243,9 @@ FFMPEG_OPTIONS = {
|
|||
FFMPEG_DEFAULT_OPTION = ASK.config.get("ffmpeg", "DefaultOption", fallback="default")
|
||||
|
||||
# TODO: CSP settings
|
||||
|
||||
# Authentication
|
||||
|
||||
LOGIN_URL = reverse_lazy("quackscape.users:login")
|
||||
LOGIN_REDIRECT_URL = reverse_lazy("quackscape.users:categories")
|
||||
LOGOUT_REDIRECT_URL = reverse_lazy("quackscape.users:login")
|
|
@ -10,7 +10,11 @@
|
|||
<div class="admin-header">
|
||||
<h2>Quackscape</h2>
|
||||
<div class="user-info">
|
||||
{% if user.is_authenticated %}
|
||||
<p>Logged in as <strong>{{ user.email }}</strong></p>
|
||||
{% else %}
|
||||
<p>Not logged in</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="container-fluid">
|
||||
|
|
38
quackscape/users/templates/users/login.html
Normal file
38
quackscape/users/templates/users/login.html
Normal file
|
@ -0,0 +1,38 @@
|
|||
{% extends "users/base.html" %} <!-- Extend from your base template if you have one -->
|
||||
|
||||
{% block content %}
|
||||
<div class="container mt-5">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="mb-0">Login</h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="post" action="{% url 'quackscape.users:login' %}">
|
||||
{% csrf_token %}
|
||||
{% if form.non_field_errors %}
|
||||
<div class="alert alert-danger">
|
||||
{% for error in form.non_field_errors %}
|
||||
{{ error }}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="mb-3">
|
||||
<label for="id_username" class="form-label">Username</label>
|
||||
<input type="text" class="form-control" name="username" id="id_username" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="id_password" class="form-label">Password</label>
|
||||
<input type="password" class="form-control" name="password" id="id_password" required>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<button type="submit" class="btn btn-primary">Login</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -1,13 +1,14 @@
|
|||
from .views import UserAreaMainView, CategoriesView, CategoryView, FileUploadView
|
||||
from .views import UserAreaMainView, CategoriesView, CategoryView, FileUploadView, Login, Logout
|
||||
|
||||
from django.urls import path
|
||||
from django.contrib.auth.views import LogoutView, LoginView
|
||||
|
||||
app_name = 'quackscape.users'
|
||||
|
||||
urlpatterns = [
|
||||
path('', UserAreaMainView.as_view(), name='user-area-main'),
|
||||
path('categories/', CategoriesView.as_view(), name='categories'),
|
||||
path('category/<uuid:category>/', CategoryView.as_view(), name='category'),
|
||||
path('category/<uuid:category>/upload/', FileUploadView.as_view(), name='media-upload'),
|
||||
path('login/', LoginView.as_view(), name='login'),
|
||||
path('logout/', LogoutView.as_view(), name='logout'),
|
||||
path('login/', Login.as_view(), name='login'),
|
||||
path('logout/', Logout.as_view(), name='logout'),
|
||||
]
|
|
@ -1,5 +1,7 @@
|
|||
from django.views.generic import TemplateView, ListView, DetailView
|
||||
from django.http import Http404
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.contrib.auth.views import LoginView, LogoutView
|
||||
|
||||
from rest_framework.parsers import MultiPartParser, FormParser
|
||||
from rest_framework.response import Response
|
||||
|
@ -21,12 +23,12 @@ class TitleMixin:
|
|||
return context
|
||||
|
||||
|
||||
class UserAreaMainView(TitleMixin, TemplateView):
|
||||
class UserAreaMainView(LoginRequiredMixin, TitleMixin, TemplateView):
|
||||
template_name = "users/base.html"
|
||||
title = "User Area"
|
||||
|
||||
|
||||
class CategoriesView(TitleMixin, ListView):
|
||||
class CategoriesView(LoginRequiredMixin, TitleMixin, ListView):
|
||||
model = Category
|
||||
template_name = "users/categories.html"
|
||||
title = "Categories"
|
||||
|
@ -42,7 +44,7 @@ class CategoriesView(TitleMixin, ListView):
|
|||
return categories
|
||||
|
||||
|
||||
class CategoryView(TitleMixin, DetailView):
|
||||
class CategoryView(LoginRequiredMixin, TitleMixin, DetailView):
|
||||
template_name = "users/category.html"
|
||||
title = "Category"
|
||||
context_object_name = "category"
|
||||
|
@ -56,17 +58,17 @@ class CategoryView(TitleMixin, DetailView):
|
|||
raise Http404()
|
||||
|
||||
|
||||
class MediaUploadView(TitleMixin, TemplateView):
|
||||
class MediaUploadView(LoginRequiredMixin, TitleMixin, TemplateView):
|
||||
template_name = "users/media_upload.html"
|
||||
title = "Upload Media"
|
||||
|
||||
|
||||
class CategoryCreateView(TitleMixin, TemplateView):
|
||||
class CategoryCreateView(LoginRequiredMixin, TitleMixin, TemplateView):
|
||||
template_name = "users/category_create.html"
|
||||
title = "Create Category"
|
||||
|
||||
|
||||
class FileUploadView(GenericAPIView):
|
||||
class FileUploadView(LoginRequiredMixin, GenericAPIView):
|
||||
parser_classes = (MultiPartParser, FormParser)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
@ -93,3 +95,10 @@ class FileUploadView(GenericAPIView):
|
|||
|
||||
else:
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class Login(TitleMixin, LoginView):
|
||||
title = "Login"
|
||||
template_name = "users/login.html"
|
||||
|
||||
class Logout(LogoutView):
|
||||
pass
|
Loading…
Reference in a new issue