web-dev-qa-db-ja.com

パスワードなしでユーザーに手動でログインする

パスワードを使用して手動で(サーバー側で開始される)ログインwithoutを実装する最良の方法を理解するのに役立つことを願っています。ワークフローを説明しましょう:

  • ユーザー登録
  • ありがとうございました!アクティベーションリンクを記載したメールが送信されました
  • (アカウントは現在存在していますが、有効になっていないとマークされています)
  • ユーザーがメールを開き、リンクをクリックします
  • (アカウントは有効です)
  • ありがとうございました!これでサイトを使用できます

私がやろうとしているのは、ユーザーが電子メールのリンクをクリックした後にログインして、すぐにWebサイトの使用を開始できるようにすることです。

DBで暗号化されているため、パスワードを使用できません。カスタム認証バックエンドを作成する唯一のオプションはありますか?

65
Agos

ユーザーのログインにパスワードは必要ありません。 auth.login function は、Userオブジェクトを取ります。アカウントを有効にすると、おそらくデータベースからすでに取得されていると思われます。したがって、それをloginに直接渡すことができます。

もちろん、very非常に注意する必要があります。ユーザーが既存の有効なアカウントへのリンクをスプーフィングできないように注意してください。そのユーザーとして自動的にログインします。

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)

...など.

編集済み

うーん、追加のプロパティがあるため、authenticateを使用する必要があることに気付きませんでした。コードを見ると、認証バックエンドのモジュールパスに相当するbackend属性のみが実行されます。だからあなたはそれを偽造することができます-上記のログイン呼び出しの前に、これをしてください:

user.backend = 'Django.contrib.auth.backends.ModelBackend'
88
Daniel Roseman

Django 1.10以降、プロセスは単純化されました。

Djangoのすべてのバージョンで、ユーザーがログインするには、 アプリのバックエンドの1つによって認証されているAUTHENTICATION_BACKENDS設定)。

単にログインを強制する場合は、そのリストの最初のバックエンドによってユーザーが認証されたと主張することができます。

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)
25
Ian Clark

ダニエルの答えはとても良いです。

それを行う別の方法は、カスタム認証バックエンドに従ってHashModelBackendを作成することです https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#writing-an-authentication-backend このような:

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

そして、これを設定にインストールします:

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

その場合、ビューは次のようになります。

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
25
dar

skaパッケージを使用できます。このパッケージは、Django=実装されています。skaは認証トークンで動作し、そのセキュリティはSHARED_KEYに基づいています。関係するすべての関係者(サーバー)に等しい。

クライアント側(パスワードなしのログインを要求するパーティ)で、skaを使用してURLを生成し、署名します。例:

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',
    }
)

トークンのデフォルトの有効期間は600秒です。 lifetime引数を証明することでカスタマイズできます。

サーバー側(ユーザーがログインするサイト)で、skaを適切にインストールしたことを念頭に置いて、ユーザーはURLが存在する場合(ユーザー名が一致する場合)、または- 。プロジェクトのDjango=設定でカスタマイズできるコールバックが3つあります。

  • USER_GET_CALLBACK(文字列):データベース(既存のユーザー)からユーザーが正常に取得された場合に発生します。
  • USER_CREATE_CALLBACK(文字列):ユーザーが作成された直後に発生しました(ユーザーは存在しませんでした)。
  • USER_INFO_CALLBACK(文字列):認証が成功すると起動します。

詳細については、ドキュメント( http://pythonhosted.org/ska/ )を参照してください。

2

danの回答への応答。

バックエンドを書く方法:

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

回答はDjango.contrib.auth.backends.ModelBackendソースコードに基づいています。 Django 1.9

そして、私はむしろDjangoのデフォルトの下にカスタムバックエンドを配置します。

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

アカウントのアクティベーションはログイン自体よりも少ないためです。 https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#specifying-authentication-backends によると:

AUTHENTICATION_BACKENDSの順序が重要であるため、同じユーザー名とパスワードが複数のバックエンドで有効な場合、Djangoは最初の一致で処理を停止します。

注意してくださいこのコードは、間違ったパスワードでもユーザーを認証します。