Manuelles Anmelden eines Benutzers ohne Passwort

73

Ich hoffe, Sie können mir helfen, den besten Weg zu finden, um eine manuelle (serverseitig initiierte) Anmeldung ohne Verwendung des Kennworts zu implementieren . Lassen Sie mich den Workflow erklären:

  • Benutzerregister
  • Vielen Dank! Eine E-Mail mit einem Aktivierungslink wurde blablabla gesendet
  • (Konto existiert jetzt, ist aber als nicht aktiviert markiert)
  • Benutzer öffnet E-Mail, klickt auf Link
  • (Konto ist aktiviert)
  • Vielen Dank! Sie können die Site jetzt verwenden

Ich versuche, den Benutzer anzumelden, nachdem er auf den E-Mail-Link geklickt hat, damit er die Website sofort nutzen kann.

Ich kann sein Kennwort nicht verwenden, da es in der Datenbank verschlüsselt ist. Ist die einzige Option, ein benutzerdefiniertes Authentifizierungs-Backend zu schreiben?

Agos
quelle
Bitte beziehen Sie sich auf den folgenden Thread: stackoverflow.com/questions/6560182/…
Sameer Kumar Choudhary

Antworten:

97

Sie benötigen kein Kennwort, um einen Benutzer anzumelden. Die auth.loginFunktion nimmt nur ein UserObjekt entgegen, das Sie vermutlich bereits aus der Datenbank erhalten, wenn Sie das Konto aktivieren. Sie können das also direkt an weitergeben login.

Natürlich müssen Sie sehr vorsichtig sein, dass ein Benutzer auf keinen Fall einen Link zu einem bereits aktivierten Konto fälschen kann, der ihn dann automatisch als diesen Benutzer anmeldet.

from django.contrib.auth import login

def activate_account(request, hash):
    account = get_account_from_hash(hash)
    if not account.is_active:
        account.activate()
        account.save()
        user = account.user
        login(request, user)

... etc.

Bearbeitet :

Hmm, habe diese Anforderung authenticatewegen der zusätzlichen Eigenschaft, die sie hinzufügt , nicht bemerkt . Wenn Sie sich den Code ansehen, ist alles, was er tut, ein backendAttribut, das dem Modulpfad des authentifizierenden Backends entspricht. Sie können es also einfach vortäuschen - tun Sie dies vor dem obigen Login-Aufruf:

user.backend = 'django.contrib.auth.backends.ModelBackend'
Daniel Roseman
quelle
1
Vielen Dank; Die Dokumente stimmen zu, aber es gibt auch die folgende Warnung: "Zuerst authenticate () aufrufen Wenn Sie einen Benutzer manuell anmelden, müssen Sie authenticate () aufrufen, bevor Sie login () aufrufen. authenticate () legt dem Benutzer ein Attribut fest, das angibt, welches Das Authentifizierungs-Backend hat diesen Benutzer erfolgreich authentifiziert (Einzelheiten finden Sie in der Backend-Dokumentation). Diese Informationen werden später während des Anmeldevorgangs benötigt. " Könnte dies ein Problem sein?
Agos
Obwohl es besser ist, Einstellungen aus django.contrib.conf zu importieren und Einstellungen zuzuweisen. AUTHENTICATION_BACKENDS, falls die Verwendung ein benutzerdefiniertes Backend hat.
Arsham
das funktioniert nicht, auch nicht modifiziert; Sie müssen ein Auth-Backend erstellen und zu Ihren Einstellungen hinzufügen. Andernfalls bleibt der Benutzer zwischen den Seitenladevorgängen nicht angemeldet.
Warath-Codierer
@ Warath-Coder Du hast recht. Ich habe wie Daniel gesagt, aber nach mehreren Ajax-Anfragen, Django Server Antwort auf das Zurücksetzen der Cookies-Sitzung auf Null, so muss sich der Benutzer abmelden. Wie kann man das lösen?
Jcyrss
1
Ab Django 1.6 scheint es erforderlich zu sein, dass die backendEinstellung tatsächlich in der Liste enthalten ist, AUTHENTICATION_BACKENDSdamit sie funktioniert.
Tim Tisdall
28

Ab Django 1.10 wurde der Prozess vereinfacht.

In allen Versionen von Django muss ein Benutzer, damit er angemeldet sein kann, von einem der Backends Ihrer App authentifiziert werden (gesteuert durch die AUTHENTICATION_BACKENDSEinstellung).

Wenn Sie einfach eine Anmeldung erzwingen möchten, können Sie einfach behaupten, dass der Benutzer vom ersten Backend aus dieser Liste authentifiziert wurde:

from django.conf import settings
from django.contrib.auth import login


# Django 1.10+
login(request, user, backend=settings.AUTHENTICATION_BACKENDS[0])

# Django <1.10 -  fake the authenticate() call
user.backend = settings.AUTHENTICATION_BACKENDS[0]
login(request, user)
Ian Clark
quelle
1
Nett! Kleiner Tippfehler. Sie haben zweimal Einstellungen. sollte seinlogin(request, user, backend=settings.AUTHENTICATION_BACKENDS[0])
Eupharis
@eupharis derp! Vielen Dank, behoben!
Ian Clark
25

Daniels Antwort ist sehr gut.

Eine andere Möglichkeit besteht darin, ein HashModelBackend nach dem Backend für benutzerdefinierte Autorisierung zu erstellen : https://docs.djangoproject.com/de/1.8/topics/auth/customizing/#writing-an-authentication-backend wie folgt :

class HashModelBackend(object):
    def authenticate(self, hash=None):
        user = get_user_from_hash(hash)
        return user

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

Und dann installieren Sie dies in Ihren Einstellungen:

AUTHENTICATION_BACKENDS = (
    'myproject.backends.HashModelBackend',
    'django.contrib.auth.backends.ModelBackend',
)

Dann wäre Ihre Ansicht ungefähr so:

def activate_account(request, hash):
    user = authenticate(hash=hash)
    if user:
        # check if user is_active, and any other checks
        login(request, user)
    else:
        return user_not_found_bad_hash_message
dar
quelle
2

Antwort auf Dans Antwort.

Eine Möglichkeit, Ihr Backend zu schreiben:

from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend

class HashModelBackend(ModelBackend):

def authenticate(self, username=None, **kwargs):
    UserModel = get_user_model()
    if username is None:
        username = kwargs.get(UserModel.USERNAME_FIELD)
    try:
        user = UserModel._default_manager.get_by_natural_key(username)
        return user
    except UserModel.DoesNotExist:
        return None

Die Antwort basiert auf dem Quellcode django.contrib.auth.backends.ModelBackend . Es ist aktuell für Django 1.9

Und ich würde lieber ein benutzerdefiniertes Backend unter die Standardeinstellung von Django stellen:

AUTHENTICATION_BACKENDS = [
    'django.contrib.auth.backends.ModelBackend',
    'yours.HashModelBackend',
]

weil die Kontoaktivierung weniger möglich ist als die Anmeldung selbst. Laut https://docs.djangoproject.com/de/1.9/topics/auth/customizing/#specifying-authentication-backends :

Die Reihenfolge von AUTHENTICATION_BACKENDS ist wichtig. Wenn also derselbe Benutzername und das gleiche Passwort in mehreren Backends gültig sind, stoppt Django die Verarbeitung beim ersten positiven Match.

Seien Sie vorsichtig, dieser Code authentifiziert Ihre Benutzer auch mit falschen Passwörtern.

Алексей Маратканов
quelle
Dieser Code enthält Syntaxfehler, daher ist nicht klar, was passieren soll ('Hash' wird definiert, aber nicht verwendet, 'Benutzername' wird verwendet, aber nicht definiert).
Amichai Schreiber
2

Sie können ein skaPaket verwenden, für das eine kennwortlose Anmeldung bei Django implementiert ist. skaarbeitet mit Authentifizierungstoken und seine Sicherheit basiert auf SHARED_KEY, das für alle beteiligten Parteien (Server) gleich sein sollte.

Auf der Clientseite (Partei, die eine kennwortlose Anmeldung anfordert) generieren Sie eine URL und signieren sie mit ska. Beispiel:

from ska import sign_url
from ska.contrib.django.ska.settings import SECRET_KEY

server_ska_login_url = 'https://server-url.com/ska/login/'

signed_url = sign_url(
    auth_user='test_ska_user_0',
    secret_key=SECRET_KEY,
    url=server_ska_login_url
    extra={
        'email': '[email protected]',
        'first_name': 'John',
        'last_name': 'Doe',
    }
)

Die Standardlebensdauer des Tokens beträgt 600 Sekunden. Sie können dies anpassen, indem Sie ein lifetimeArgument beweisen .

Auf der Serverseite (Site, bei der sich Benutzer anmelden) wird skader Benutzer beim ordnungsgemäßen Installieren beim Aufrufen der URL angemeldet, sofern vorhanden (Benutzername-Übereinstimmung) oder auf andere Weise erstellt. Es gibt 3 Rückrufe, die Sie in den Django-Einstellungen Ihres Projekts anpassen können.

  • USER_GET_CALLBACK (Zeichenfolge): Wird ausgelöst, wenn der Benutzer erfolgreich aus der Datenbank abgerufen wurde (vorhandener Benutzer).
  • USER_CREATE_CALLBACK (Zeichenfolge): Wird direkt nach dem Erstellen des Benutzers ausgelöst (Benutzer war nicht vorhanden).
  • USER_INFO_CALLBACK (Zeichenfolge): Wird bei erfolgreicher Authentifizierung ausgelöst.

Weitere Informationen finden Sie in der Dokumentation ( http://pythonhosted.org/ska/ ).

Artur Barseghyan
quelle