django.contirb.auth-認証

6771 ワード

まずmiddlewareの定義を見てみましょう.
authモジュールには、2つのmiddlewareがあります.AuthenticationMiddlewareとSessionAuthenticationMiddlewareです.
AuthenticationMiddlewareはrequestにuserプロパティを追加する責任を負います
class AuthenticationMiddleware(object):
    def process_request(self, request):
        assert hasattr(request, 'session'), (
            "The Django authentication middleware requires session middleware "
            "to be installed. Edit your MIDDLEWARE_CLASSES setting to insert "
            "'django.contrib.sessions.middleware.SessionMiddleware' before "
            "'django.contrib.auth.middleware.AuthenticationMiddleware'."
        )
        request.user = SimpleLazyObject(lambda: get_user(request))

AuthenticationMiddlewareは、sessionがユーザー情報を格納する必要があるため、session属性によって最初にチェックされることがわかります.
userプロパティの追加はget_に遅延されましたuser()関数にあります.SimpleLazyObjectは遅延技術である.
次のように定義されています.
セッション検証を担当します
class SessionAuthenticationMiddleware(object):
    """
    Middleware for invalidating a user's sessions that don't correspond to the
    user's current session authentication hash (generated based on the user's
    password for AbstractUser).
    """
    def process_request(self, request):
        user = request.user
        if user and hasattr(user, 'get_session_auth_hash'):
            session_hash = request.session.get(auth.HASH_SESSION_KEY)
            session_hash_verified = session_hash and constant_time_compare(
                session_hash,
                user.get_session_auth_hash()
            )
            if not session_hash_verified:
                auth.logout(request)

userのget_を比較するsession_auth_方法とsessionの中のauth.HASH_SESSION_KEY属性は,ユーザのセッションが正しいか否かを判断する.
requestの中のuserオブジェクトについては、どのような属性があるか、get_を見る必要があります.user()関数の定義.
def get_user(request):
    if not hasattr(request, '_cached_user'):
        request._cached_user = auth.get_user(request)
    return request._cached_user

明らかにget_userメソッドはrequestに追加されました_cached_userプロパティ.キャッシュとして使用されます.
ユーザ認証にはデータベースを照会し,ユーザの情報を得る必要があるため,オーバーヘッドを減らす必要がある.
なお、このキャッシュは、同じrequestに対してのみ、すなわち、1つのviewでrequestに複数回アクセスする.userプロパティ.
httpリクエストのたびに新しいリクエストが表示されます.
次はauth.get_user()メソッドの定義、requestを深く理解する.userというオブジェクト:
def get_user(request):
    """
    Returns the user model instance associated with the given request session.
    If no user is retrieved an instance of `AnonymousUser` is returned.
    """
    from .models import AnonymousUser
    user = None
    try:
        user_id = request.session[SESSION_KEY]
        backend_path = request.session[BACKEND_SESSION_KEY]
    except KeyError:
        pass
    else:
        if backend_path in settings.AUTHENTICATION_BACKENDS:
            backend = load_backend(backend_path)
            user = backend.get_user(user_id)
    return user or AnonymousUser()

まず、クライアントとサーバがセッションメカニズムを確立したと仮定します.このセッションのSESSION_KEY属性は、userのid番号です.
このセッションのBACKEND_SESSION_KEY属性は,どのバックグラウンド技術を用いてユーザ情報を取得するかを指定する.最後にbackendを使用します.get_user()はuserを取得します.満たされていない場合は、AnonymousUserオブジェクトを返します.
このuserを取得するプロセスには,まずクライアントとサービス側がsessionメカニズムを確立しなければならないという前提がある.では、このsessionメカニズムはどのように構築されていますか?
このセッションが確立されたプロセスはauthです.login関数では、
def login(request, user):
    """
    Persist a user id and a backend in the request. This way a user doesn't
    have to reauthenticate on every request. Note that data set during
    the anonymous session is retained when the user logs in.
    """
    session_auth_hash = ''
    if user is None:
        user = request.user
    if hasattr(user, 'get_session_auth_hash'):
        session_auth_hash = user.get_session_auth_hash()

    if SESSION_KEY in request.session:
        if request.session[SESSION_KEY] != user.pk or (
                session_auth_hash and
                request.session.get(HASH_SESSION_KEY) != session_auth_hash):
            # To avoid reusing another user's session, create a new, empty
            # session if the existing session corresponds to a different
            # authenticated user.
            request.session.flush()
    else:
        request.session.cycle_key()
    request.session[SESSION_KEY] = user.pk
    request.session[BACKEND_SESSION_KEY] = user.backend
    request.session[HASH_SESSION_KEY] = session_auth_hash
    if hasattr(request, 'user'):
        request.user = user
    rotate_token(request)

まず,ユーザ認証に関連するセッションがあるかどうかを判断し,ある場合はデータを空にし,ない場合は新規に作成する.
次にsessionの値:SESSION_と書きますKEY, BACKEND_SESSION_KEY, HASH_SESSION_KEY.
次に、ログイン時にauthを使用する一般的な方法について説明します.
from django.contrib.auth import authenticate, login 
def login_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(username=username, password=password)
    if user is not None:
        login(request, user)
        #  
    else:        #  

一般的なコミットはPOST方式でコミットされ、authenticateメソッド検証が呼び出され、成功した後loginを使用してセッションが作成されます.
引き続きauthenticateの定義を見てみましょう.
def authenticate(**credentials):
    """
    If the given credentials are valid, return a User object.
    """
    for backend in get_backends():
        try:
            inspect.getcallargs(backend.authenticate, **credentials)
        except TypeError:
            # This backend doesn't accept these credentials as arguments. Try the next one.
            continue

        try:
            user = backend.authenticate(**credentials)
        except PermissionDenied:
            # This backend says to stop in our tracks - this user should not be allowed in at all.
            return None
        if user is None:
            continue
        # Annotate the user object with the path of the backend.
        user.backend = "%s.%s" % (backend.__module__, backend.__class__.__name__)
        return user

    # The credentials supplied are invalid to all backends, fire signal
    user_login_failed.send(sender=__name__,
            credentials=_clean_credentials(credentials))

backendsをポーリングし、backendのauthenticateメソッドを呼び出して認証します.
注意userのbackendプロパティは、ユーザーがどのbackend認証方式を使用しているかを示す後に更新されます.その値はlogin関数に格納され、セッションのBACKEND_に格納されます.SESSION_KEY属性にあります.
backendのauthenticateメソッドで返されるuserには、この属性はありません.
最後にログイン後のauthの使い方を説明します.ログイン時のauthの使い方を示しており,ログイン後にsessionメカニズムが確立される.したがってrequestのuser属性を直接取得することで,ユーザの情報や状態を判断することができる.
def my_view(request):
    if request.user.is_authenticated():
        #  
    else:    
        #