缺少所需参数状态Python社交认证电子邮件验证

时间:2015-08-01 23:03:53

标签: python django python-social-auth

我正在使用django app的python social auth。在电子邮件验证中,邮件收到的链接在启动身份验证的同一浏览器中正常工作,但在不同的浏览器中显示Missing needed parameter state。是否有人解决此问题?

这里讨论的问题是Issue #577

1 个答案:

答案 0 :(得分:1)

这是因为其他浏览器中没有部分管道数据!

Christopher Keefer通过获取Django会话表的session_key来为monkey-patch工作。还有关于此的博客文章here,请参阅本文的第3步。

# Monkey patching - an occasionally necessary evil.
from social import utils
from social.exceptions import InvalidEmail

from django.core import signing
from django.core.signing import BadSignature
from django.contrib.sessions.models import Session
from django.conf import settings


def partial_pipeline_data(backend, user=None, *args, **kwargs):
    """
    Monkey-patch utils.partial_pipeline_data to enable us to retrieve session data by signature key in request.
    This is necessary to allow users to follow a link in an email to validate their account from a different
    browser than the one they were using to sign up for the account, or after they've closed/re-opened said
    browser and potentially flushed their cookies. By adding the session key to a signed base64 encoded signature
    on the email request, we can retrieve the necessary details from our Django session table.
    We fetch only the needed details to complete the pipeline authorization process from the session, to prevent
    nefarious use.
    """
    data = backend.strategy.request_data()
    if 'signature' in data:
        try:
            signed_details = signing.loads(data['signature'], key=settings.EMAIL_SECRET_KEY)
            session = Session.objects.get(pk=signed_details['session_key'])
        except BadSignature, Session.DoesNotExist:
            raise InvalidEmail(backend)

        session_details = session.get_decoded()
        backend.strategy.session_set('email_validation_address', session_details['email_validation_address'])
        backend.strategy.session_set('next', session_details.get('next'))
        backend.strategy.session_set('partial_pipeline', session_details['partial_pipeline'])
        backend.strategy.session_set(backend.name + '_state', session_details.get(backend.name + '_state'))
        backend.strategy.session_set(backend.name + 'unauthorized_token_name',
                                     session_details.get(backend.name + 'unauthorized_token_name'))

    partial = backend.strategy.session_get('partial_pipeline', None)
    if partial:
        idx, backend_name, xargs, xkwargs = \
            backend.strategy.partial_from_session(partial)
        if backend_name == backend.name:
            kwargs.setdefault('pipeline_index', idx)
            if user:  # don't update user if it's None
                kwargs.setdefault('user', user)
            kwargs.setdefault('request', backend.strategy.request_data())
            xkwargs.update(kwargs)
            return xargs, xkwargs
        else:
            backend.strategy.clean_partial_pipeline()
utils.partial_pipeline_data = partial_pipeline_data

这在很大程度上解决了问题,但仍然不完美。如果session_key在数据库中被删除/更改,它将失败。每当会话数据发生变化时,Django都会更新session_key。因此,如果任何其他用户登录同一浏览器,session_key将被更改,用户无法通过电子邮件链接进行验证。

Omab在issue

的评论中提到过
  

我现在看到了问题,即使我认为这可以通过重写电子邮件验证管道来解决,这会影响使用部分机制的所有管道功能,所以,我已经处理将改善此行为的管道序列化功能的重组。基本上,管道数据将被转储到数据库表,并且哈希代码将用于标识可以停止并稍后继续的进程,从而消除会话的依赖性。

正在寻找更新。