[PYTHON] So aktualisieren Sie Benutzerinformationen bei der Django RemoteUserMiddleware-Anmeldung

Hintergrund

Verwenden Sie RemoteUserMiddleware, um SSO mit Django durchzuführen.

Auf der Django-App-Seite wird der Benutzer anhand der Umgebungsvariablen REMOTE_USER identifiziert, die vom SAML-Modul (Shibboleth in der eigenen Umgebung) als ID-Informationen festgelegt wurde. Zu diesem Zeitpunkt sind jedoch auch andere Attribute als die ID-Informationen (z. B. E-Mail) in der Benutzerklasse auf der Django-App-Seite enthalten. Ich möchte es einfangen.

In Verbindung stehender Artikel: Django + Shibboleth mit RemoteUserMiddleware (Erläuterung der Einführung von RemoteUserMiddleware)

Umgebung

--Windows Server 2016 (nicht direkt verwandt)

Vorausgesetztes Wissen

RemoteUserBackend durchsucht das durch settings.AUTH_USER_MODEL angegebene Benutzermodell nach einem Objekt, dessen Benutzername die Umgebungsvariable REMOTE_USER enthält. Wenn gefunden, melden Sie sich als dieser Benutzer an. Wenn nicht gefunden, erstellen Sie ein Benutzerobjekt mit REMOTE_USER als Benutzername und melden Sie sich an (diese Einstellung kann geändert werden).

Schritt 1: Überschreiben Sie configure_user

Ursprünglich verwendet "RemoteUserBackend" die Methode zum Bearbeiten des Benutzerobjekts beim Erstellen des Benutzerobjekts auf der Seite der Django-App.

python:django.contrib.auth.backends


class RemoteUserBackend(ModelBackend):
...
    def configure_user(self, request, user):
        """
        Configure a user after creation and return the updated user.

        By default, return the user unmodified.
        """
        return user

Erstellen Sie "backends.py" (einen beliebigen Namen) in einer geeigneten App.

appname
└── appname
    ├── templates
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    ├── views.py
    ├── wsgi.py
    └── backends.py  #← Erstellen

Überschreiben Sie configure_user. Dieses Mal habe ich beschlossen, das von Shibboleth hinzugefügte Attribut "ATR_mail`" in den HTTP-Header im User-Objekt einzugeben.

backends.py


from django.contrib.auth.backends import RemoteUserBackend

class MyRemoteUserBackend(RemoteUserBackend):
    def configure_user(self, request, user: MyUser):
        user.email = request.META['ATR_mail']
        user.save() #← Vergiss nicht! !!
        return user

Um dies zu aktivieren, müssen Sie AUTHENTICATION_BACKENDS in settings.py ändern.

settings.py


AUTHENTICATION_BACKENDS = (
    # 'django.contrib.auth.backends.RemoteUserBackend', #← Löschen
    'appname.backends.MyRemoteUserBackend', #← Hinzufügen
    'django.contrib.auth.backends.ModelBackend',
)

Schritt 2: Überschreiben Sie "Authentifizieren"

Durch einfaches Überschreiben von "configure_user" wird "configure_user" nur ausgeführt, wenn Sie ein neues Benutzerobjekt für REMOTE_USER erstellen, das für Django neu ist, und sich anmelden. ** ** **

Das vorhandene Benutzerobjekt wird nicht aktualisiert, selbst wenn sich die Attributinformationen auf der IdP-Seite ändern. Dies scheint jedoch in vielen Fällen unpraktisch zu sein. Wenn Sie beispielsweise SSO in einem Unternehmen verwenden und sich die Abteilungs- oder Nebenstellennummer von Zeit zu Zeit ändert.

In diesem Fall müssen Sie "authentifizieren" ändern. Glücklicherweise können Sie das zuvor erstellte "MyRemoteUserBackend" von "backends.py" verwenden. Die meisten sind Kopien von "authentifizieren" von "RemoteUserBackend" der Superklasse.

backends.py


from django.contrib.auth.backends import RemoteUserBackend

from django.contrib.auth.models import User

import inspect
import warnings

from django.contrib.auth import get_user_model
from django.utils.deprecation import RemovedInDjango31Warning

UserModel = get_user_model()

class MyRemoteUserBackend(RemoteUserBackend):

    def authenticate(self, request, remote_user):
        """
        The username passed as ``remote_user`` is considered trusted. Return
        the ``User`` object with the given username. Create a new ``User``
        object if ``create_unknown_user`` is ``True``.

        Return None if ``create_unknown_user`` is ``False`` and a ``User``
        object with the given username is not found in the database.
        """
        if not remote_user:
            return
        user = None
        username = self.clean_username(remote_user)

        # Note that this could be accomplished in one try-except clause, but
        # instead we use get_or_create when creating unknown users since it has
        # built-in safeguards for multiple threads.
        if self.create_unknown_user:
            user, created = UserModel._default_manager.get_or_create(**{
                UserModel.USERNAME_FIELD: username
            })
            if created:                                      #← Achtung
                args = (request, user)
                try:
                    inspect.getcallargs(self.configure_user, request, user)
                except TypeError:
                    args = (user,)
                    warnings.warn(
                        'Update %s.configure_user() to accept `request` as '
                        'the first argument.'
                        % self.__class__.__name__, RemovedInDjango31Warning
                    )
                user = self.configure_user(*args)            #← Achtung
            else:                                            #← Hinzufügen
                user = self.configure_user(request, user)    #← Hinzufügen
        else:
            try:
                user = UserModel._default_manager.get_by_natural_key(username)
            except UserModel.DoesNotExist:
                pass
        return user if self.user_can_authenticate(user) else None

    def configure_user(self, request, user: User):
        user.email = request.META['ATR_mail']
        user.save()
        return user

Wie in "Achtung" angegeben, wird "configure_user" ursprünglich nur aufgerufen, wenn "created == True" in "UserModel._default_manager.get_or_create". Auf diese Weise können Sie vorhandene Benutzerinformationen nicht aktualisieren.

Fügen Sie daher zwei Zeilen "add" hinzu, damit "configure_user" auch dann aufgerufen wird, wenn "created! = True". Wenn Sie den Vorgang zum Erstellen und Aktualisieren eines neuen Benutzerobjekts trennen möchten, können Sie "configure_user" imitieren und einen neuen "update_user" usw. erstellen, damit es aufgerufen wird.

das ist alles.

Recommended Posts

So aktualisieren Sie Benutzerinformationen bei der Django RemoteUserMiddleware-Anmeldung
Übergeben Sie Login-Benutzerinformationen, um sie in Django anzuzeigen
So aktualisieren Sie Spyder in Anaconda
Wie man CSS in Django reflektiert
So geben Sie zusätzliche Informationen aus, wenn Sie Protokolle mit dem Protokollierungsmodul von Python ausgeben
So löschen Sie abgelaufene Sitzungen in Django
So führen Sie vom Server gesendete Ereignisse in Django durch
Benutzerinformationen usw. in das Django-Protokoll ausgeben
So implementieren Sie Rails-Helfer-ähnliche Funktionen in Django
[Django] So beheben Sie Fehler bei der Installation von mysqlclient
So reflektieren Sie ImageField in Django + Docker (Kissen)
So erstellen Sie eine Rest-API in Django
So verbergen Sie Benutzereingaben in der PySimple-Benutzeroberfläche
[Django-Memo] Ich möchte die angemeldeten Benutzerinformationen im Voraus im Formular festlegen.
So aktualisieren Sie easy_install
So aktualisieren Sie Spyder
Aktualisieren Sie die Django-Version 1.11.1 auf 2.2
So erhalten Sie mehrere Modellobjekte zufällig in Django
Zugriff mit dem Cache beim Lesen von_json mit Pandas
Verwendung von Bootstrap in der generischen Klassenansicht von Django
Beenden bei Verwendung von Python in Terminal (Mac)
Hochladen von Dateien in der generischen Klassenansicht von Django
Wie man Decorator in Django benutzt und wie man es macht
So verweisen Sie auf statische Dateien in einem Django-Projekt
Verwendung von Fixture in Django zur Eingabe von Beispieldaten für das Benutzermodell
So schreiben Sie eine benutzerdefinierte Validierung in Django REST Framework
Umgang mit statischen Dateien bei der Bereitstellung in der Produktion mit Django
Verwendung von Laravel-ähnlichem ORM / Query Builder Orator mit Django
Wie aktualisiere ich mit SQLAlchemy?
[Django] Wie man Eingabewerte im Voraus mit ModelForm angibt
So lösen Sie den CSRF-Schutz bei Verwendung von AngularJS mit Django
So generieren Sie eine Abfrage mit dem IN-Operator in Django
So geben Sie Befehlszeilenargumente beim Debuggen mit PyCharm an
Was tun, wenn in Django "Ungültiger HTTP_HOST-Header" angezeigt wird?
Wie man in Django die angezeigte lange Zeichenkette in der Mitte abkürzt ....
Wie man in Python entwickelt
Ändern Sie die Meldung, die beim Anmelden bei Raspberry Pi angezeigt wird
Wie man Japanern nicht entgeht, wenn man mit json in Python umgeht
Erfassen Sie das Betriebsprotokoll automatisch im Terminal, wenn Sie sich bei Linux anmelden
[Linux] Ich möchte das Datum wissen, an dem sich der Benutzer angemeldet hat
So zeigen Sie Formeln in Latex an, wenn Sie sympy (> = 1.4) in Google Colaboratory verwenden
[Django] Lesen von Variablen / Konstanten, die in einer externen Datei definiert sind
So stellen Sie eine Django-App in nur 5 Minuten für Heroku bereit
Wie man sich verbessert, wenn Spyders Editor in Mavericks sehr schwer ist
[Tipps] Die Vorgehensweise beim Erstellen von HTML mit Django wird erweitert
[Python] Wie man PCA mit Python macht
Umgang mit Sitzungen in SQLAlchemy
[Django] So testen Sie Form [TDD]
Verwendung von Klassen in Theano
Wie man nüchtern mit Pandas schreibt
So sammeln Sie Bilder in Python
Fehler im Zusammenhang mit Memcached in Django
Verwendung von SQLite in Python
Verwendung des Python-Protokollierungsmoduls
So fügen Sie sudo hinzu, wenn Sie das Debug ausführen
So konvertieren Sie 0,5 in 1056964608 auf einmal
Wie fange ich mit Django an?
Wie man Prozesse in großen Mengen abbricht