首页 文章

是否需要python-social-auth的会话

提问于
浏览
18

我试图将python-social-auth(PSA)与django-rest-framework-jwt(DRFJWT)集成在一起,所以我的目标是让auth流向此:

用户通过角度客户端登录Email / facebook - >客户帖子表格到PSA的网址 - > PSA登录/创建用户 - > [!] DRFJWT创建令牌然后发送回客户端 - >客户端将令牌存储在本地存储中然后使用令牌每个请求

[!]:这是我正在努力的地方 . 我的想法是我可以像这样修改PSA中的do_complete方法

from rest_framework_jwt.utils import jwt_payload_handler, jwt_encode_handler


def do_complete(backend, login, user=None, redirect_name='next',
            *args, **kwargs):
  # pop redirect value before the session is trashed on login()
  data = backend.strategy.request_data()
  redirect_value = backend.strategy.session_get(redirect_name, '') or \
                 data.get(redirect_name, '')

  is_authenticated = user_is_authenticated(user)
  user = is_authenticated and user or None

  partial = partial_pipeline_data(backend, user, *args, **kwargs)
  if partial:
      xargs, xkwargs = partial
      user = backend.continue_pipeline(*xargs, **xkwargs)
  else:
      user = backend.complete(user=user, *args, **kwargs)

  if user_is_active(user):
      # catch is_new/social_user in case login() resets the instance
      is_new = getattr(user, 'is_new', False)
      social_user = user.social_user
      login(backend, user, social_user)

  payload = jwt_payload_handler(user)
  return { 'token': jwt_encode_handler(payload) }

这是做我想要完成的事情的唯一方法吗?

我也想知道从最佳实践角度来看,使用会话来管理管道和JWT是否可以使用?

2 回答

  • 5

    我也使用python-social-authdjango-rest-framework-jwt进行用户身份验证 .

    我能够将两个身份验证系统集成在一起的方式是创建一个自定义视图,该视图接收oAuth提供程序提供的“ access_token ”并尝试使用它创建新用户 . 创建用户后,我返回JWT令牌,而不是返回经过身份验证的用户/会话 .

    以下代码片段解释了解决方案 .

    后端

    在我的 views.py 文件中,我包括以下内容:

    @psa()
    def auth_by_token(request, backend):
        """Decorator that creates/authenticates a user with an access_token"""
        token = request.DATA.get('access_token')
        user = request.user
        user = request.backend.do_auth(
                access_token=request.DATA.get('access_token')
            )
        if user:
            return user
        else:
            return None
    
    class FacebookView(views.APIView):
        """View to authenticate users through Facebook."""
    
        permission_classes = (permissions.AllowAny,)
    
        def post(self, request, format=None):
            auth_token = request.DATA.get('access_token', None)
            backend = request.DATA.get('backend', None)
            if auth_token and backend:
                try:
                    # Try to authenticate the user using python-social-auth
                    user = auth_by_token(request, backend)
                except Exception,e:
                    return Response({
                            'status': 'Bad request',
                            'message': 'Could not authenticate with the provided token.'
                        }, status=status.HTTP_400_BAD_REQUEST)
                if user:
                    if not user.is_active:
                        return Response({
                            'status': 'Unauthorized',
                            'message': 'The user account is disabled.'
                        }, status=status.HTTP_401_UNAUTHORIZED)
    
                    # This is the part that differs from the normal python-social-auth implementation.
                    # Return the JWT instead.
    
                    # Get the JWT payload for the user.
                    payload = jwt_payload_handler(user)
    
                    # Include original issued at time for a brand new token,
                    # to allow token refresh
                    if api_settings.JWT_ALLOW_REFRESH:
                        payload['orig_iat'] = timegm(
                            datetime.utcnow().utctimetuple()
                        )
    
                    # Create the response object with the JWT payload.
                    response_data = {
                        'token': jwt_encode_handler(payload)
                    }
    
                    return Response(response_data)
            else:
                return Response({
                        'status': 'Bad request',
                        'message': 'Authentication could not be performed with received data.'
                }, status=status.HTTP_400_BAD_REQUEST)
    

    在我的 urls.py 中,我包括以下路线:

    urlpatterns = patterns('',
        ...
        url(r'^api/v1/auth/facebook/', FacebookView.as_view()),
        ...
    )
    

    前端

    现在,后端身份验证已连线,您可以使用任何前端库发送access_token并对用户进行身份验证 . 就我而言,我使用了AngularJS .

    在控制器文件中,我调用API如下:

    /**
    * This function gets called after successfully getting the access_token from Facebook's API.
    */
    function successLoginFbFn(response) {
        var deferred = $q.defer();
        $http.post('/api/v1/auth/facebook/', {
            "access_token": response.authResponse.accessToken, 
            "backend": "facebook"
        }).success(function(response, status, headers, config) {
            // Success
            if (response.token) {
                // Save the token to localStorage and redirect the user to the front-page.
                Authentication.setToken(response.token);
                window.location = '/';
            }
            deferred.resolve(response, status, headers, config);
        }).error(function(response, status, headers, config) {
            // Error
            console.error('Authentication error.');
            deferred.reject(response, status, headers, config);
        });
    }
    

    使用这种方法,您可以混合使用两个插件 . 所有发送的令牌都将来自django-rest-framework-jwt,即使用户仍然可以通过Facebook,Google,Twitter等网站提供的身份验证自己 .

    我只展示了通过Facebook进行身份验证的方法,但是您可以对其他提供商采用类似的方法 .

  • 7

    不,您不需要使用python-social-auth的会话(标准Django登录系统) . 您需要使JWT和PSA协同工作的是DRF .

    这是我的解决方案:

    我使用标准PSA的网址来提出请求太社交 /login/(?P<backend>[^/]+)/$ ,更改了 urls.py 中的网址以匹配从Facebook / Twitter到我自己的重定向 .

    url(r'^complete/(?P<backend>[^/]+)/$', views.SocialAuthViewComplete.as_view()),
    

    使用API的目的是在PSA正在执行的请求中访问用户数据 . 如果您在 DEFAULT_AUTHENTICATION_CLASSES 中进行了JWT身份验证,则DRF允许您执行此操作

    REST_FRAMEWORK = {
              'DEFAULT_AUTHENTICATION_CLASSES': (
                  'rest_framework.authentication.SessionAuthentication',
                  'rest_framework.authentication.TokenAuthentication',
                  'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),}
    

    views.py

    from social.apps.django_app.views import complete
    
    class SocialAuthViewComplete(APIView):
        permission_classes = ()
    
        def post(self, request, backend, *args, **kwargs):
            try:
                #Wrap up  PSA's `complete` method.    
                authentication = complete(request, backend, *args, **kwargs)
            except Exception, e:
                exc = {
                    'error': str(e)
                }
                return Response(exc, status=status.HTTP_400_BAD_REQUEST)
            return Response({'data': authentication}, status=status.HTTP_202_ACCEPTED)
    

    然后我_________方法中的 do_complete 方法:

    def do_complete(backend, login, user=None, redirect_name='next',
                    *args, **kwargs):
        # pop redirect value before the session is trashed on login()
        data = backend.strategy.request_data()
        redirect_value = backend.strategy.session_get(redirect_name, '') or \
                         data.get(redirect_name, '')
    
        is_authenticated = user_is_authenticated(user)
        user = is_authenticated and user or None
    
        partial = partial_pipeline_data(backend, user, *args, **kwargs)
        if partial:
            xargs, xkwargs = partial
            user = backend.continue_pipeline(*xargs, **xkwargs)
        else:
            user = backend.complete(user=user, *args, **kwargs)
    
        user_model = backend.strategy.storage.user.user_model()
        if user and not isinstance(user, user_model):
            return user
    
        if is_authenticated:
            if not user:
                information =  'setting_url(backend, redirect_value, LOGIN_REDIRECT_URL'
            else:
                information =  'setting_url(backend, redirect_value, NEW_ASSOCIATION_REDIRECT_URL,LOGIN_REDIRECT_URL'
        elif user:
            # Get the JWT payload for the user.
            payload = jwt_payload_handler(user)
    
            if user_is_active(user):
                is_new = getattr(user, 'is_new', False)
                if is_new:
                    information = 'setting_url(backend, NEW_USER_REDIRECT_URL, redirect_value, LOGIN_REDIRECT_URL'
                else:
                    information = 'setting_url(backend, redirect_value, LOGIN_REDIRECT_URL'
            else:
                return Response({
                            'status': 'Unauthorized',
                            'message': 'The user account is disabled.'
                        }, status=status.HTTP_401_UNAUTHORIZED)
        else:
            information = 'setting_url(backend, LOGIN_ERROR_URL, LOGIN_URL'
    
    
        return { 'an information i may use in future': information,
                 'token': jwt_encode_handler(payload) # Create the response object with the JWT payload.
        }
    

    tried 管道和用户关联,它正常工作 . 如果您需要它来与JWT一起使用,您也可以从PSA修改另一种方法 .

相关问题