基于Django默认用户表实现WordPress与Django同域单点登录
同域下基于Django默认用户表实现与WordPress的自动会话同步(无需WP-API)
核心思路
因为是同域环境,我们可以在Django用户登录成功后,直接完成两个关键操作:
- 将Django用户同步到WordPress的用户表(不存在则创建)
- 生成符合WordPress规则的会话Cookie,让WordPress识别用户已登录
步骤1:配置跨库访问(Django连接WordPress数据库)
首先在Django的settings.py中添加WordPress数据库的配置(两者用同数据库可跳过此配置):
DATABASES = { 'default': { # 你的Django数据库配置 }, 'wp': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'wordpress_db_name', 'USER': 'wp_db_user', 'PASSWORD': 'wp_db_password', 'HOST': 'localhost', 'PORT': '3306', } }
同时把WordPress的密钥配置到Django中(从WordPress的wp-config.php里复制AUTH_KEY和SECURE_AUTH_KEY):
WORDPRESS_AUTH_KEY = '你的WordPress AUTH_KEY' WORDPRESS_SECURE_AUTH_KEY = '你的WordPress SECURE_AUTH_KEY' DOMAIN = '.example.com' # 同域根域名,比如主站是example.com,子域统一用这个
步骤2:同步Django用户到WordPress
在Django的登录视图中,处理用户登录成功后的同步逻辑。注意要兼容WordPress的密码哈希规则:
from django.contrib.auth import authenticate, login from django.db import connections from django.shortcuts import redirect, render import hashlib import random import time from django.conf import settings from django.utils.http import http_date import hmac def wordpress_hash_password(password): # 模拟WordPress的PHPass哈希逻辑(兼容新旧版本WP) salt = hashlib.sha1(str(random.random()).encode()).hexdigest()[:8] hash_str = hashlib.md5((password + salt).encode()).hexdigest() return f'$P${salt}${hash_str}' def custom_login(request): if request.method == 'POST': username = request.POST['username'] password = request.POST['password'] user = authenticate(request, username=username, password=password) if user is not None: login(request, user) # 同步用户到WordPress数据库 with connections['wp'].cursor() as cursor: # 检查用户是否已存在于WP表中 cursor.execute("SELECT ID FROM wp_users WHERE user_login = %s", [user.username]) wp_user_row = cursor.fetchone() if not wp_user_row: # 创建WordPress用户 wp_hashed_pwd = wordpress_hash_password(password) cursor.execute(""" INSERT INTO wp_users (user_login, user_pass, user_nicename, user_email, user_registered) VALUES (%s, %s, %s, %s, NOW()) """, [user.username, wp_hashed_pwd, user.username, user.email]) wp_user_id = cursor.lastrowid # 同步基础用户元数据(可选) cursor.execute("INSERT INTO wp_usermeta (user_id, meta_key, meta_value) VALUES (%s, %s, %s)", [wp_user_id, 'first_name', user.first_name]) cursor.execute("INSERT INTO wp_usermeta (user_id, meta_key, meta_value) VALUES (%s, %s, %s)", [wp_user_id, 'last_name', user.last_name]) else: wp_user_id = wp_user_row[0] # 生成并设置WordPress会话Cookie response = set_wordpress_session_cookie(request, wp_user_id, user.username) return response # GET请求返回登录页面 return render(request, 'login.html')
步骤3:生成WordPress会话Cookie
编写函数生成符合WordPress规则的登录Cookie,确保WordPress能识别用户身份:
def set_wordpress_session_cookie(request, wp_user_id, username): auth_key = settings.WORDPRESS_AUTH_KEY secure_auth_key = settings.WORDPRESS_SECURE_AUTH_KEY domain = settings.DOMAIN # 生成logged_in Cookie的哈希值 cookie_hash = hmac.new(auth_key.encode(), f"{wp_user_id}|{username}".encode(), hashlib.sha256).hexdigest() expiration = int(time.time()) + 86400 * 14 # 两周有效期,和WP默认一致 cookie_value = f"{wp_user_id}|{expiration}|{cookie_hash}|{username}" # 生成Cookie名称(WP会根据域名生成前缀) cookie_name_prefix = hmac.new(auth_key.encode(), domain.encode(), hashlib.md5).hexdigest()[:32] logged_in_cookie_name = f'wordpress_logged_in_{cookie_name_prefix}' # 设置基础登录Cookie response = redirect('/') response.set_cookie( logged_in_cookie_name, cookie_value, expires=http_date(expiration), domain=domain, path='/', secure=request.is_secure(), httponly=True, samesite='Lax' ) # HTTPS环境下添加secure Cookie if request.is_secure(): secure_cookie_prefix = hmac.new(secure_auth_key.encode(), domain.encode(), hashlib.md5).hexdigest()[:32] secure_cookie_name = f'wordpress_sec_{secure_cookie_prefix}' response.set_cookie( secure_cookie_name, cookie_value, expires=http_date(expiration), domain=domain, path='/', secure=True, httponly=True, samesite='Lax' ) return response
步骤4:同步登出(可选)
在Django登出时,清除WordPress的会话Cookie,确保两边状态一致:
from django.contrib.auth import logout def custom_logout(request): logout(request) response = redirect('/') domain = settings.DOMAIN auth_key = settings.WORDPRESS_AUTH_KEY secure_auth_key = settings.WORDPRESS_SECURE_AUTH_KEY # 清除logged_in Cookie cookie_prefix = hmac.new(auth_key.encode(), domain.encode(), hashlib.md5).hexdigest()[:32] response.delete_cookie(f'wordpress_logged_in_{cookie_prefix}', domain=domain, path='/') # 清除HTTPS环境下的secure Cookie if request.is_secure(): secure_prefix = hmac.new(secure_auth_key.encode(), domain.encode(), hashlib.md5).hexdigest()[:32] response.delete_cookie(f'wordpress_sec_{secure_prefix}', domain=domain, path='/') return response
关键注意事项
- 同域配置:WordPress的
wp-config.php中必须设置define('COOKIE_DOMAIN', '.example.com');,Django的settings.py设置SESSION_COOKIE_DOMAIN = '.example.com'和CSRF_COOKIE_DOMAIN = '.example.com',确保Cookie跨子域共享。 - 密码哈希兼容:如果你的WordPress使用PHP 5.5+的
password_hash()(而非旧版PHPass),需要调整wordpress_hash_password函数,或者直接调用PHP脚本生成哈希(比如用subprocess执行简单的PHP脚本)。 - 用户信息同步:如果Django用户修改了邮箱、密码等信息,需要通过Django的
post_save信号同步到WordPress,避免两边数据不一致。
内容的提问来源于stack exchange,提问作者Aditya Prakash Gupta
相关产品推荐
相关产品推荐

