django会话保持依赖两个中间件SessionMiddleware
和AuthenticationMiddleware。
SessionMiddleware:用于session的校验和下发(下发至request.session)
AuthenticationMiddleware:
通过request.session获取用户对象,并比对此时用户认证和session中存储的认证是否相同.
正常使用中的登陆、退出和会话保持
from django.contrib.auth import authenticate, login , logout
def login(request):
if request.method == "POST":
username = request.POST.get('username', '')
password = request.POST.get('password', '')
user = authenticate(username=username, password=password) # 验证用户帐号密码是否正确,通过后返回User对象
if not user:
login(request, user) # 登录,response添加cookie并将session_key记录到django_session
request.session.set_expiry(0) # 设置session失效时间,0表示关闭浏览器失效
return HttpResponseRedirect('/')
from django.contrib.auth import authenticate, login , logout
def logout(request):
logout(request) # 清除response的cookie和django_session中记录
return HttpResponseRedirect('/login')
MIDDLEWARE = (
# 获取cookie中sessionid对应的django_session并做校验,有效的时候会把session对象增加到request.session
'django.contrib.sessions.middleware.SessionMiddleware',
# 根据request.session获取对应User并校验是否有效
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
AuthenticationMiddleware源码:
HASH_SESSION_KEY = '_auth_user_hash'
# auth.get_user
def get_user(request):
"""
Return the user model instance associated with the given request session.
If no user is retrieved, return an instance of `AnonymousUser`.
"""
from .models import AnonymousUser
user = None
try:
user_id = _get_user_session_key(request)
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)
# Verify the session
if hasattr(user, 'get_session_auth_hash'):
session_hash = request.session.get(HASH_SESSION_KEY)
session_hash_verified = session_hash and constant_time_compare(
session_hash,
user.get_session_auth_hash()
)
if not session_hash_verified:
request.session.flush()
user = None
return user or AnonymousUser()
也就是session_hash_verified = session_hash and constant_time_compare(session_hash,user.get_session_auth_hash())
,对比session._auth_user_hash
和user.get_session_auth_hash()
是否相同, django_session
中session_data
默认存储的如下信息:
{
'_auth_user_id': '25',
'_auth_user_backend': 'django.contrib.auth.backends.ModelBackend',
'_auth_user_hash': '54332f14831144a4022e7601c6dd3fcc531a5454',
'_session_expiry': 0
}
user.get_session_auth_hash()
如下(User的父类):
class AbstractBaseUser(models.Model):
def get_session_auth_hash(self):
"""
Return an HMAC of the password field.
"""
key_salt = "django.contrib.auth.models.AbstractBaseUser.get_session_auth_hash"
return salted_hmac(key_salt, self.password).hexdigest()
那么影响hash的就是user.password,django这么做就是要实现修改密码强制用户自动退出。