3

Facebook アカウントが正常に動作しているときに、Twitter アカウントに登録しようとすると、部分的なパイプラインで 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 は電子メール アドレスを公開しますが、Twitter は公開しないため、Facebook と連携します。そのため、リダイレクトを行うエントリの前にそのメソッドを追加するか、リダイレクトを行う前にパイプライン コード内で呼び出します。

(コメントを回答として投稿して選択できるようにするだけです)

于 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 に答える