更新登录逻辑,等待数据库进一步完善

This commit is contained in:
2025-11-10 13:38:44 +08:00
parent f3aec9a18d
commit 1bbd777565
6 changed files with 52 additions and 29 deletions

20
accounts/crypto.py Normal file
View File

@@ -0,0 +1,20 @@
import hashlib
import hmac
def salt_for_username(username: str) -> bytes:
"""Derive a per-username salt using SHA-256(username).
The salt is deterministic for a given username and does not require storage.
"""
return hashlib.sha256(username.encode('utf-8')).digest()
def derive_password(password_plain: str, salt: bytes, iterations: int = 100_000, dklen: int = 32) -> bytes:
"""PBKDF2-SHA256 derive a fixed-length secret from a plaintext password and salt."""
return hashlib.pbkdf2_hmac('sha256', password_plain.encode('utf-8'), salt, iterations, dklen=dklen)
def hmac_sha256(key: bytes, message: bytes) -> bytes:
"""Compute HMAC-SHA256 signature for the given message using key bytes."""
return hmac.new(key, message, hashlib.sha256).digest()

View File

@@ -1,14 +1,6 @@
import base64
import hashlib
from elastic.es_connect import get_user_by_username as es_get_user_by_username
def _salt_for_username(username: str) -> bytes:
return hashlib.sha256(username.encode('utf-8')).digest()
def _derive_password(password_plain: str, salt: bytes) -> bytes:
return hashlib.pbkdf2_hmac('sha256', password_plain.encode('utf-8'), salt, 100_000, dklen=32)
from .crypto import salt_for_username, derive_password
def get_user_by_username(username: str):
@@ -16,18 +8,27 @@ def get_user_by_username(username: str):
从Elasticsearch获取用户数据
"""
# 首先尝试从ES获取用户数据
es_user = es_get_user_by_username(username)
salt = _salt_for_username(username)
derived = _derive_password(es_user.get('password', ''), salt)
if es_user:
# 如果ES中有用户数据使用ES中的密码
return {
'user_id': es_user.get('user_id', 0),
'username': es_user.get('username', ''),
'password': base64.b64encode(derived).decode('ascii'),
'premission': es_user.get('permission', 1),
'salt': base64.b64encode(salt).decode('ascii'),
}
# es_user = es_get_user_by_username(username)
# if es_user:
# salt = salt_for_username(username)
# derived = derive_password(es_user.get('password', ''), salt)
# # 如果ES中有用户数据使用ES中的密码
# return {
# 'user_id': es_user.get('user_id', 0),
# 'username': es_user.get('username', ''),
# 'password': base64.b64encode(derived).decode('ascii'),
# 'permission': es_user.get('permission', 1),
# }
salt = salt_for_username('admin')
derived = derive_password('admin', salt)
return {
'user_id': 0,
'username': 'admin',
'password': base64.b64encode(derived).decode('ascii'),
'permission': 0,
}
return None

View File

@@ -81,6 +81,7 @@ document.getElementById('loginForm').addEventListener('submit', async (e) => {
const csrftoken = getCookie('csrftoken');
const chalResp = await fetch('/accounts/challenge/', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken || ''
@@ -102,6 +103,7 @@ document.getElementById('loginForm').addEventListener('submit', async (e) => {
// Step 3: submit login with username and hmac
const submitResp = await fetch('/accounts/login/submit/', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken || ''

View File

@@ -1,6 +1,7 @@
import base64
import json
import os
import hmac
from django.http import JsonResponse, HttpResponseBadRequest
from django.shortcuts import render, redirect
@@ -8,7 +9,8 @@ from django.views.decorators.http import require_http_methods
from django.views.decorators.csrf import csrf_protect
from django.conf import settings
from .es_client import get_user_by_username, _salt_for_username
from .es_client import get_user_by_username
from .crypto import salt_for_username, hmac_sha256
@require_http_methods(["GET"])
@@ -30,7 +32,7 @@ def challenge(request):
# Generate nonce and compute per-username salt
nonce = os.urandom(16)
salt = _salt_for_username(username)
salt = salt_for_username(username)
# Persist challenge in session to prevent replay with mismatched user
request.session["challenge_nonce"] = base64.b64encode(nonce).decode("ascii")
@@ -71,10 +73,7 @@ def login_submit(request):
nonce = base64.b64decode(nonce_b64)
stored_derived_b64 = user.get("password", "")
stored_derived = base64.b64decode(stored_derived_b64)
# HMAC-SHA256: server computes with stored derived secret
import hmac, hashlib
server_hmac = hmac.new(stored_derived, nonce, hashlib.sha256).digest()
server_hmac_b64 = base64.b64encode(server_hmac).decode("ascii")
server_hmac_b64 = base64.b64encode(hmac_sha256(stored_derived, nonce)).decode("ascii")
except Exception:
return HttpResponseBadRequest("Verification error")
@@ -89,7 +88,7 @@ def login_submit(request):
request.session["user_id"] = user["user_id"]
request.session["username"] = user["username"]
request.session["premission"] = user["premission"]
request.session["permission"] = user["permission"]
# Clear challenge to prevent reuse
for k in ("challenge_username", "challenge_nonce"):

View File

@@ -38,6 +38,7 @@
try {
const resp = await fetch('/accounts/logout/', {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken || ''

View File

@@ -6,7 +6,7 @@ from django.views.decorators.http import require_http_methods
def home(request):
# Enforce login: require session user_id
session_user_id = request.session.get("user_id")
if not session_user_id:
if session_user_id is None:
return redirect("/accounts/login/")
# Show user_id (prefer query param if present, but don't trust it)