# Настройка доступа для пользователей --- ## Разграничение записей по пользователям ---- 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 примите меры к тому, чтобы каждое сообщение в блоге было связано с конкретным пользователем. Убедитесь в том, что чтение всех сообщений доступно всем пользователям, но только зарегистрированные пользователи могут создавать новые и редактировать существующие сообщения. В представлении, в котором пользователи редактируют сообщения, перед обработкой формы убедитесь в том, что редактируемое сообщение принадлежит именно этому пользователю.
{"metaMigratedAt":"2023-06-16T13:28:33.250Z","metaMigratedFrom":"Content","title":"Настройка доступа для пользователей","breaks":true,"contributors":"[{\"id\":\"0d39d5a3-691d-488c-8f1e-1a0fb0be4f13\",\"add\":7462,\"del\":229}]"}
    490 views