session 修改密码python_django修改密码强制退出机制
起因
BUG出現
系統升級django版本后經常出現自動退出登錄
問題復現
系統升級django(大版本,如1.8、1.11和2.0)后,舊版與新版同時運行,同一各User用舊版authenticate驗證后會導致新版中已登錄User被退出。
正常使用中的登陸、退出和會話保持
登錄
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')
保持登陸狀態
成功登錄后瀏覽器將在每次請求時Header中附帶cookie
settings.py配置:
SECRET_KEY = '%iai=j+uyd4s0t3qm$3w-w6^b0lf!df%hh-@5f!0&4enc(o7#5'# key變化密碼的hash也會變
MIDDLEWARE = (
# ... 無關部分省略
'django.contrib.sessions.middleware.SessionMiddleware', # 獲取cookie中sessionid對應的django_session,有效的時候會把session對象增加到request.session
'django.contrib.auth.middleware.AuthenticationMiddleware',# 根據request.session獲取對應User并校驗是否有效
# ... 無關部分省略
)
尋根溯源
具體過程比較曲折,一言難盡。
會話保持依賴兩個中間件SessionMiddleware和AuthenticationMiddleware,其中AuthenticationMiddleware通過request.session獲取用戶對象,并比對此時用戶認證和session中存儲的認證是否相同
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這么做原本是要實現修改密碼強制用戶自動退出。django文檔
修改密碼強制用戶自動退出的特性在django 2.0之前版本需要添加'django.contrib.auth.middleware.SessionAuthenticationMiddleware'到 MIDDLEWARE_CLASSES才能啟用此特性,2.0開始移除此中間件并強制啟用此特性
當用戶密碼被修改后,hash變化,判斷為session失效
當不同版本django中authenticate()時會自動重新生成密碼的密文,導致數據庫中密碼密文變化,hash也變化,判斷為session失效,這就是文章開始bug的原因
升級django密碼密文變化原因d
繞過修改密碼強制退出的方法
兩種方法
方法1: 每次請求不嚴重hash(僅適用于自定義User的) 屏蔽user.get_session_auth_hash()方法,使跳過hash比對
class User(AbstractBaseUser):
# ... 無關的省略
def __getattribute__(self, item):
if item == 'get_session_auth_hash':
raise AttributeError
return super().__getattribute__(item)
方法2: 保證不同版本密碼密文一致 settings.py
PASSWORD_HASHERS = [
'core.password.CustomPBKDF2PasswordHasher',
]
core.password.py
from django.contrib.auth.hashers import PBKDF2PasswordHasher
class CustomPBKDF2PasswordHasher(PBKDF2PasswordHasher):
iterations = 20000# 所有系統指定此值為一樣,能使密碼密文不變
總結
以上是生活随笔為你收集整理的session 修改密码python_django修改密码强制退出机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑打开html不显示图片,网页不显示图
- 下一篇: AM335X-IO输入总是读不到输入电平