我在用PHP实现Django用户认证。基于cookie的认证方案安全吗?
我有一个用PHP写的网站,现在想用Python和Django添加一些新功能。其中一部分是使用Django的标准认证包来处理用户登录。
当用户通过我们的Django系统登录后,他们如果访问PHP的部分,我需要确认他们已经登录,并且能够使用数据库中的用户信息。
我该如何从PHP获取用户ID,并验证Django的会话ID是否有效,利用Django的sessionid这个cookie值呢?
我的计划是在用户登录时,将Django的会话ID、我的Django密钥和用户ID做一个哈希值。这个哈希值会作为一个额外的cookie保存。然后在PHP中,我会提取用户ID,计算这个ID、密钥和Django的sessionid cookie值的哈希值,并进行比较,看它们是否一致。
我扩展了认证登录的视图,让它在用户成功登录后设置一个额外的cookie。这样就不再是HttpResponseRedirect,而是返回HttpResponseSetAuthCookieAndRedirect。
HttpResponseSetAuthCookieAndRedirect会获取request.session.session_id和user_id作为参数。
class HttpResponseSetAuthCookieAndRedirect(HttpResponse):
""" a cookie enhanced version of HttpResponseRedirect """
status_code = 302
def __init__(self, user_id, session_id, redirect_to):
HttpResponse.__init__(self)
self['Location'] = iri_to_uri(redirect_to)
my_hash=hashlib.sha512('{0}|-|{1}|-|{2}'.format(settings.SECRET_KEY,user_id,session_id)).hexdigest()
cookie_hash="{0}::{1}".format(user_id,my_hash[:64])
self.set_cookie('check', value=cookie_hash, max_age=172800, path='/', domain=None)
这样就设置了一个cookie,这个cookie是会话ID、我的Django密钥和经过认证的用户ID的哈希值,且这个用户ID与会话ID匹配。
在PHP中,
$check_cookie=$_COOKIE['check'];
$django_cookie=$_COOKIE['sessionid'];
$check_cookie=str_replace('"','',$check_cookie);
$django_cookie=str_replace('"','',$django_cookie); //they have quotes for some reason
$parts=explode('::',$check_cookie);
$sent_user_id=(int)$parts[0];
$sent_hash=$parts[1];
$cookie_hash=hash('sha512',"$secret_key|-|$sent_user_id|-|$dj_cookie_sessionid");
$reconstructed_security_hash=$sent_user_id.'::'.substr($cookie_hash,0,64);
if($reconstructed_security_hash==$cookie_hash)
{
return $sent_user_id; //cookies are valid, and user id is the one set by Django for this session id.
}
return false; //cookies do not match
到目前为止,这个方法是有效的。
这个想法靠谱吗?
2 个回答
你知道有没有办法做一个解决方案,可以让你在一个PHP应用程序里登录后,直接用这个登录信息去另一个Django应用程序登录,而不用再输入用户名和密码吗?
如果你能在PHP中解码Django在会话中存储的数据,那么你就可以直接从数据库中获取相关的会话数据(使用来自cookie的会话ID),这样你就能直接知道哪个用户登录了Django网站——如果有的话。
编辑:
这是Django使用的“加密”方式:
在“解密”之后,你应该能得到类似这样的内容:
{
'_auth_user_id': 123,
'_auth_user_backend': 'django.contrib.auth.backends.ModelBackend',
}
——当然还有你自己设置的其他会话数据