2015-12-24 28 views
10

Tài liệu django-rest-auth thảo luận về tích hợp Facebook mà tôi không quan tâm-- mối lo ngại của tôi là cung cấp thông tin đăng nhập xã hội qua Google. Tôi đã thử điều này trong một thời gian và tôi tự hỏi liệu có ai khác có tài liệu về cách họ làm điều này ... thậm chí chỉ là một bản phác thảo thô sơ sẽ hữu ích. Cho đến nay, tôi đã không tìm thấy bất kỳ kết quả nào cho tìm kiếm này. Tôi gần như ở đó, nhưng không thể làm cho nó hoạt động được với API có thể duyệt của khung công tác còn lại Django (DRF).django-rest-auth: đăng nhập xã hội với google

Dưới đây là những gì tôi có cho đến thời điểm này: Tôi bắt đầu từ dự án demo được cung cấp trên trang django-rest-auth github và sửa đổi trang HTML mẫu đăng nhập xã hội để chỉ yêu cầu đầu vào 'mã' chứ không phải cả hai mã 'AND' access_token '. Khi tôi cung cấp một mã hợp lệ (thu được bởi một yêu cầu riêng biệt đến điểm cuối auth của google), điều này hoạt động tốt; API có thể duyệt sẽ hiển thị trang web thông thường bằng 'khóa' (mã thông báo API của ứng dụng của tôi cho người dùng) trong phản hồi. Kiểm tra quản trị django, mọi thứ đã hoạt động - người dùng đã đăng nhập, email được xác thực, v.v. Tốt cho đến nay.

Vấn đề là điểm bắt đầu cung cấp 'mã' và cách tôi nhận mã đó từ google ngay từ đầu. Khi tôi trước đây (thành công) đã sử dụng gói allauth, tôi có thể chỉ cần nhấp vào liên kết, sẽ "vô hình" thực hiện toàn bộ luồng OAuth2 (tức là yêu cầu mã, sử dụng mã đó để nhận mã thông báo truy cập và sử dụng mã thông báo truy cập vào nhận thông tin tài khoản google của người dùng). Để tạo lại luồng liền mạch đó (nghĩa là KHÔNG bắt đầu với mã), tôi đã tìm ra tôi có thể làm gián đoạn luồng OAuth2 và "chặn" mã trả về từ google, sau đó POST mã đó tới API đăng nhập xã hội còn lại auth . Cuối cùng, tôi đã tạo ra một tùy chỉnh allauth.socialaccount.providers.oauth2.views.OAuth2CallbackView bằng cách ghi đè các phương pháp công văn:

class CustomOAuth2CallbackView(OAuth2CallbackView): 
    def dispatch(self, request): 
     # gets the code correctly: 
     code = request.GET['code'] 

     # rp is of type requests.methods.Response 
     rp = requests.post(<REST-AUTH API ENDPOINT>, data = {'code':code}) 
     return rp 

Thông thường, phương pháp này được gọi khi google sẽ gửi một yêu cầu GET đến uri callback bạn bước đầu cung cấp cho thiết bị đầu cuối auth của google. Với ghi đè này, tôi có thể phân tích thành công mã được trả lại từ google trong cuộc gọi lại đó. Yêu cầu POST hoạt động và có khóa của người dùng trong trường resp._content. Tuy nhiên, cuối cùng nó không thể tạo ra khung nhìn dự định trong API có thể duyệt DRF.

Dựa trên lặn xuống trong callstack, tôi thấy rằng rest_framework.views.APIView.dispatch trả về đối tượng thuộc loại rest_framework.response.Response. Tuy nhiên, khi phương pháp requests.post được sử dụng ở trên hoàn thành, nó trả về một thể hiện loại requests.models.Response. Kết quả là, nó không có các thuộc tính thích hợp và thất bại trong middleware django. Ví dụ, nó không có thuộc tính acceptable_renderer và không có phương thức 'get' (được sử dụng trong django.middleware.clickjacking.py). Tôi có thể, có thể hình dung được, thêm những yêu cầu này vào ví dụ requests.models.Response (rp), nhưng sau đó hack này trở nên nhiều hơn một kludge.

Cảm ơn bạn đã trợ giúp bạn có thể cung cấp!

+2

Did bạn nhận được bất cứ nơi nào với điều này? – jfunk

+0

Thật không may là không. Có bận rộn với những thứ khác và nó rơi ra khỏi radar của tôi. May mắn không phải là một thứ quan trọng, nhưng tôi chắc rằng những người khác có thể quan tâm đến điều này. –

Trả lời

1

https://github.com/st4lk/django-rest-social-auth

class SocialLoginSignup(SocialSessionAuthView): 
""" 
    Mobile user social signup and login api view 

    args: 
     provider: name of the social network 
     access_token: auth token got from the social sites 
""" 
serializer_class = SocialSignUpSerializer 
authentication_classes = (TokenAuthentication,) 

def post(self, request, *args, **kwargs): 
    serializer = self.serializer_class(data=request.data) 
    serializer.is_valid(raise_exception=True) 
    provider_name = serializer.validated_data['provider'] 

    decorate_request(request, provider_name) # assign the provider class object in request 

    authed_user = request.user if not request.user.is_anonymous() else None 

    token = serializer.validated_data['access_token'] 

    if self.oauth_v1() and request.backend.OAUTH_TOKEN_PARAMETER_NAME not in serializer.validated_data: 
     request_token = parse_qs(request.backend.set_unauthorized_token()) 
     return Response(request_token) 

    try: 
     # authentication function get call from assign class object in request 
     user = request.backend.do_auth(token, user=authed_user) 
    except social_exceptions.AuthException as e: 
     raise exceptions.ParseError({'error':str(e)}) 
    except social_exceptions.AuthTokenError as e: 
     raise exceptions.ParseError({'error': str(e)}) 
    except social_exceptions.AuthAlreadyAssociated as e: 
     raise exceptions.ParseError({'error': str(e)}) 
    except social_exceptions.AuthFailed as e: 
     raise exceptions.ParseError({'error':str(e)}) 
    except social_exceptions.AuthUnknownError as e: 
     raise exceptions.ParseError({'error': str(e)}) 
    except social_exceptions.WrongBackend as e: 
     raise exceptions.ParseError({'error':str(e)}) 
    except Exception as e: 
     raise exceptions.ParseError({'error': social_message.INVALID_AUTH_TOKEN}) 

    token, created = Token.objects.get_or_create(user=user) 
    return Response({'auth_token':token.key}) 
Các vấn đề liên quan