Django позволяет легко ограничить доступ к определенным страницам для пользователей, выполнивших вход, с помощью декоратора @login_required. Добавьте следующий код в learning_logs/views.py:
Добавьте следующий код в learning_logs/views.py:
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from .models import Topic, Entry
@login_required
def topics(request):
"""Выводит все темы."""
...
Чтобы перенаправление работало, необходимо внести изменения settings.py и сообщить Django, где искать страницу входа. Добавьте следующий фрагмент в самый конец settings.py:
settings.py
...
LOGIN_URL = '/users/login/'
Вот как выглядит файл learning_logs/views.py с декораторами @login_required, примененными к каждому представлению, кроме index():
@login_required
def topics(request):
...
@login_required
def topic(request, topic_id):
...
@login_required
def new_topic(request):
...
@login_required
def new_entry(request, topic_id):
...
@login_required
def edit_entry(request, entry_id):
...
Изменим модель Topic и добавим отношение внешнего ключа к пользователю. После этого необходимо провести миграцию базы данных.
from django.db import models
from django.contrib.auth.models import User
class Topic(models.Model):
text = models.CharField(max_length=200)
date_added = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.text
class Entry(models.Model):
...
В настоящее время пользователь, выполнивший вход, будет видеть все темы независимо от того, под какой учетной записью он вошел.
Внесите следующее изменение в функцию topics() в файле views.py:
@login_required
def topics(request):
topics = Topic.objects.filter(owner=request.user).order_by('date_added')
context = {'topics': topics}
return render(request, 'learning_logs/topics.html', context)
...
Никаких реальных ограничений на доступ к страницам еще не существует, поэтому любой зарегистрированный пользователь может опробовать разные URL (например, http://localhost:8000/topics/1/) и просмотреть страницы тем, которые ему удастся подобрать.
Чтобы решить эту проблему, мы будем выполнять проверку перед получением запрошенных данных в функции представления topic():
from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.http import Http404
...
@login_required
def topic(request, topic_id):
topic = Topic.objects.get(id=topic_id)
if topic.owner != request.user:
raise Http404
entries = topic.entry_set.order_by('-date_added')
context = {'topic': topic, 'entries': entries}
return render(request, 'learning_logs/topic.html', context
Страницы edit_entry используют URL-адреса в форме http://localhost:8000/edit_entry/entry_id/, где entry_id — число. Защитим эту страницу, чтобы никто не мог подобрать URL для получения доступа к чужим записям:
...
@login_required
def edit_entry(request, entry_id):
entry = Entry.objects.get(id=entry_id)
topic = entry.topic
if topic.owner != request.user:
raise Http404
if request.method != 'POST':
...
В настоящее время страница добавления новых тем не совершенна, потому что она не связывает новые темы с конкретным пользователем. При попытке добавить новую тему выдается сообщение об ошибке IntegrityError с уточнением NOT NULL constraint failed: learning_logs_topic.owner_id.
Добавьте следующий код, связывающий новую тему с текущим пользователем:
@login_required
def new_topic(request):
if request.method != 'POST':
form = TopicForm()
else:
form = TopicForm(data=request.POST)
if form.is_valid():
new_topic = form.save(commit=False)
new_topic.owner = request.user
new_topic.save()
return redirect('learning_logs:topics')
context = {'form': form}
return render(request, 'learning_logs/new_topic.html', context)
Home - контроллер-функция
HomePageView - контроллер-класс
urlpatterns = [
path('', Home, name='home'),
path('<str:week>/', HomePageView, name='specific_home'),
]
class Lessons(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.RESTRICT, verbose_name='власник')
date = models.DateField(verbose_name='дата')
teacher = models.CharField(max_length=100,
completion = models.BooleanField(default = False, verbose_name='заняття проведено')
def __str__(self):
return str('власник:' + str(self.owner.username) + ' викладач:' + str(self.teacher) + ' дата:' + str(self.date))
class Meta:
unique_together = ('date', 'lecture', 'room')
verbose_name='Заняття'
{% if user.is_authenticated%}
{% if user.first_name != '' or user.last_name != '' %}
<a class="navbar-brand ml-auto mr-4" href="{% url 'user_profile' user.pk %}"> {{ user.last_name }} {{ user.first_name }} </a>
{%else%}
<a class="navbar-brand ml-auto mr-4" href="{% url 'user_profile' user.pk %}"> {{ user.username }} </a>
{% if user.is_superuser %}
<div><a class="btn btn-light btn-block fa fa-wrench" href="/admin/" role="button"></a></div>
<a class="navbar-brand ml-4" href="{% url 'logout' %}"> Вийти </a>
{% else %}
<a class="navbar-brand ml-auto" href="{% url 'login' %}">Увійти</a>
<label> Пара
</br><select size="1" name='pair'>
{% for pair, rooms in data.items %}
<option value=pair>{{pair}} пара</option>
{%endfor%}
</select>
</label></br>
if self.request.method == "GET" and self.request.GET['marktype'] == 'check':
lection = Lessons.objects.filter(id=self.request.GET['pk'])
lection.completion = True
lection.save()
Рефакторинг: в views.py есть два места, в которых программа проверяет, что пользователь, связанный с темой, является текущим пользователем. Поместите код этой проверки в функцию с именем check_topic_owner() и вызовите эту функцию при необходимости.
Защита new_entry: пользователь может попытаться добавить новую запись в журнал другого пользователя, вводя URL-адрес с идентификатором темы, принадлежащей другому пользователю. Чтобы предотвратить подобные атаки, перед сохранением новой записи проверьте, что текущий пользователь является владельцем темы, к которой относится запись.
Защищенный блог: в проекте Blog примите меры к тому, чтобы каждое сообщение в блоге было связано с конкретным пользователем. Убедитесь в том, что чтение всех сообщений доступно всем пользователям, но только зарегистрированные пользователи могут создавать новые и редактировать существующие сообщения. В представлении, в котором пользователи редактируют сообщения, перед обработкой формы убедитесь в том, что редактируемое сообщение принадлежит именно этому пользователю.