3

当我尝试注册 twitter 帐户而 facebook 帐户工作正常时,我的部分管道中出现 KeyError。这很奇怪,因为同样的功能在 facebook 用户中运行良好。

错误信息如下:

/myapp/ 'partial_pipeline' 处的 KeyError

在'myapp_auth_form',我的代码是:

设置.py

SOCIAL_AUTH_ENABLED_BACKENDS=('facebook','twitter',)
SOCIAL_AUTH_DEFAULT_USERNAME='new_social_auth_user'

...

TWITTER_CONSUMER_KEY = 'mytwitterconsumerkey'
TWITTER_CONSUMER_SECRET = 'mytwitterconsumersecret'

LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '/'
LOGIN_ERROR_URL = '/login-error/'

SOCIAL_AUTH_PIPELINE = (
    'social_auth.backends.pipeline.social.social_auth_user',
    'social_auth.backends.pipeline.misc.save_status_to_session',
    'myapp.pipeline.has_email',
    'myapp.pipeline.check_by_email',
    'myapp.pipeline.redirect_to_form',
    'myapp.pipeline.get_username',
    'myapp.pipeline.create_user',
    'social_auth.backends.pipeline.social.associate_user',
    'social_auth.backends.pipeline.social.load_extra_data',
    'social_auth.backends.pipeline.user.update_user_details'
)

myapp.pipeline

from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse

from social_auth.models import UserSocialAuth
from registration.models import UserProfile


def has_email(details, user=None, *args, **kwargs):
    """Check if email is provided and ask for it otherwise
    """
    if user:
        return None

    email = details.get('email')
    if email:
        kwargs['request'].session['saved_email'] = email
    else:
        session = kwargs['request'].session
        email = session.get('saved_email')

    if not email:
        return HttpResponseRedirect(reverse('myapp_email_form'))

def check_by_email(details, user=None, user_exists=UserSocialAuth.simple_user_exists, *args, **kwargs):
    """Check if there's user with same email address and ask for its password to associate
    """
    if user:
        return None

    session = kwargs['request'].session

    email = session.get('saved_email')

    if email:
        if user_exists(username=email):
            return HttpResponseRedirect(reverse('myapp_auth_form'))

def redirect_to_form(*args, **kwargs):
    """Redirect to get password if user is None
    """
    session = kwargs['request'].session
    if not session.get('saved_password') and not session.get('saved_nickname') and not session.get('saved_sex') and kwargs.get('user') is None:
        return HttpResponseRedirect(reverse('social_auth_form'))

def get_username(details, user=None, *args, **kwargs):
    """Return an username for new user. Return current user username
    if user was given.
    Returns email address since myapp uses email for username
    """
    if user:
        return {'username': user.username}

    username = details.get('email') or ''

    return {'username': username}

def create_user(backend, details, response, uid, username, user=None, *args, **kwargs):
    """Create user and user profile. Depends on get_username pipeline."""
    if user:
        return {'user': user}
    if not username:
        return None

    request = kwargs['request']

    password = request.session.get('saved_password') or ''
    user = UserSocialAuth.create_user(username=username, email=username, password=password)

    nickname = request.session.get('saved_nickname') or ''
    sex = request.session.get('saved_sex') or 'F'
    profile = UserProfile.objects.create(user = user, nickname = nickname, sex = sex)

    referee_nickname = request.session.get('saved_referee') or False
    # if there was a recommender
    if referee_nickname:
        try:
            referee_profile = UserProfile.objects.get(nickname=referee_nickname)
            profile.referee = referee_profile.user
            profile.save()
        except UserProfile.DoesNotExist:
            pass

    return {
        'user': user,
        'is_new': True
    }

视图.py

from social_auth.utils import setting
from django.contrib.auth import authenticate, login

def myapp_email_form(request):
    # if user is logged in already, redirect the user to home
    if request.user.is_authenticated():
        if request.GET.get('mobile', False):
            return HttpResponseRedirect(reverse('m_home'))
        return HttpResponseRedirect(reverse('home'))
    """ If email is unprovided, ask for it
    """
    if request.method == 'POST':
        form = EmailForm(request.POST)

        if form.is_valid():
            email = form.cleaned_data['email']

            name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
            request.session['saved_email'] = email
            backend = request.session[name]['backend']
            return redirect('socialauth_complete', backend=backend)
    else:
        form = EmailForm()
        email = request.session.get('saved_email') or ''

    variables = RequestContext(request, {
        'form': form,
        'email': email,
    })

    if request.is_mobile or request.GET.get('mobile', False):
        return render_to_response('mobile/registration/social/email_form.html', variables, context_instance=RequestContext(request))

    return render_to_response('.../email_form.html', variables, context_instance=RequestContext(request))

def myapp_auth_form(request):
    # if user is logged in already, redirect the user to home
    if request.user.is_authenticated():
        if request.GET.get('mobile', False):
            return HttpResponseRedirect(reverse('m_home'))
        return HttpResponseRedirect(reverse('home'))
    """ If user's email is already registered to myapp, ask user for its password
    """
    if request.method == 'POST':
        form = LoginForm(request.POST)

        if form.is_valid():
            email = form.cleaned_data['username']
            user = authenticate(username=email, password=form.cleaned_data['password'])

            if user is not None:
                if user.is_active:
                    login(request, user)

                    name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
                    request.session['saved_user'] = user
                    ############################################
                    backend = request.session[name]['backend'] #<- I'm getting the KeyError at this point
                    ############################################
                    return redirect('socialauth_complete', backend=backend)
                else:
                    return HttpResponseRedirect(reverse('inactive_user'))
            else:
                form.non_field_errors = _('A user with such email and password does not exist.')
    else:
        form = LoginForm()
        email = request.session.get('saved_email') or ''

    variables = RequestContext(request, {
        'form': form,
        'email': email,
    })

    if request.is_mobile or request.GET.get('mobile', False):
        return render_to_response('mobile/registration/social/auth_form.html', variables, context_instance=RequestContext(request))

    return render_to_response('.../auth_form.html', variables, context_instance=RequestContext(request))

def social_auth_form(request):
    # if user is logged in already, redirect the user to home
    if request.user.is_authenticated():
        if request.GET.get('mobile', False):
            return HttpResponseRedirect(reverse('m_home'))
        return HttpResponseRedirect(reverse('home'))
    """ Remedy form taking missing information during social authentication
    """
    nickname = ''
    sex = 'F'

    if request.method == 'POST':
        form = SocialRegistrationForm(request.POST)

        if form.is_valid():
            nickname = form.cleaned_data['nickname']
            sex = form.cleaned_data['sex']

            name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
            request.session['saved_nickname'] = nickname
            request.session['saved_sex'] = sex
            request.session['saved_password'] = form.cleaned_data['password1']
            backend = request.session[name]['backend']
            return redirect('socialauth_complete', backend=backend)
    else:
        form = SocialRegistrationForm()

        nickname = request.session.get('saved_username') or ''
        sex = request.session.get('saved_gender') or 'F'

        if sex == 'male':
            sex = 'M'
        elif sex == 'female':
            sex = 'F'

    variables = RequestContext(request, {
        'form': form,
        'nickname': nickname,
        'sex': sex,
    })

    if request.is_mobile or request.GET.get('mobile', False):
        return render_to_response('mobile/registration/social/social_form.html', variables, context_instance=RequestContext(request))

    return render_to_response('.../auth_form.html', variables, context_instance=RequestContext(request))
4

2 回答 2

4

您需要'social_auth.backends.pipeline.misc.save_status_to_session'在每个发出重定向并停止进程的方法之前添加。它适用于 Facebook,因为 Facebook 会公开电子邮件地址,但 Twitter 不会。因此,在执行重定向的任何条目之前添加该方法,或者在执行重定向之前在管道代码中调用它。

(只需发布评论作为答案,以便可以选择)

于 2013-05-09T20:41:47.717 回答
0

您收到以下错误,因为您尝试使用 this 访问会话名称request.session[name]。假设该格式用于存储会话。为了解决这个问题,

name = setting('SOCIAL_AUTH_PARTIAL_PIPELINE_KEY', 'partial_pipeline')
request.session['saved_user'] = user
############################################
request.session['name'] = name 
backend = request.session.get('name') // this is the session format in getting the data
############################################
return redirect('socialauth_complete', backend=backend)
于 2013-03-18T09:22:00.963 回答