How can I use Django OAuth Toolkit with Python Social Auth?

后端 未结 4 2029
小蘑菇
小蘑菇 2020-11-28 01:05

I\'m building an API using Django Rest Framework. Later this API is supposed to be consumed by iOS and Android devices. I want to allow my users to sign-up with oauth2-provi

相关标签:
4条回答
  • 2020-11-28 01:31

    I was doing React Native with expo and Django with Django REST framework. This blogpost ended being the way I solved registration (signup) with facebook https://medium.com/@gabriel_gamil/react-native-expo-django-facebook-authentication-sign-in-83625c49da7

    tldr; use django-rest-auth https://django-rest-auth.readthedocs.io/en/latest/index.html

    use Django-allauth https://django-allauth.readthedocs.io/en/latest/

    0 讨论(0)
  • 2020-11-28 01:32

    I solved it by using your A. option.

    What I do is registering users that use a third party to sign up by their third party access token.

    url(r'^register-by-token/(?P<backend>[^/]+)/$',
        views.register_by_access_token),
    

    This way, I can issue a GET request like this one:

    GET http://localhost:8000/register-by-token/facebook/?access_token=123456

    And register_by_access_token gets called. request.backend.do_auth will query the provider for the user info from the token and magically register a user account with the info or sign in the user if he's already registered.

    Then, I create a token manually and return it as JSON for letting the client query my API.

    from oauthlib.common import generate_token
    ...
    @psa('social:complete')
    def register_by_access_token(request, backend):
        # This view expects an access_token GET parameter, if it's needed,
        # request.backend and request.strategy will be loaded with the current
        # backend and strategy.
        third_party_token = request.GET.get('access_token')
        user = request.backend.do_auth(third_party_token)
    
        if user:
            login(request, user)
    
            # We get our app!   
            app = Application.objects.get(name="myapp")
    
            # We delete the old token
            try:
                old = AccessToken.objects.get(user=user, application=app)
            except:
                pass
            else:
                old.delete()
    
            # We create a new one
            my_token = generate_token()
    
            # We create the access token 
            # (we could create a refresh token too the same way) 
            AccessToken.objects.create(user=user,
                                       application=app,
                                       expires=now() + timedelta(days=365),
                                       token=my_token)
    
            return "OK" # you can return your token as JSON here
    
        else:
            return "ERROR"
    

    I'm just not sure about the way I generate the token, is this good practice? Well, in the mean time, it works!!

    0 讨论(0)
  • 2020-11-28 01:33

    Maybe django-rest-framework-social-oauth2 is what you're looking for. This package depends on python-social-auth and django-oauth-toolkit, which you already use. I quickly scanned through the documentation, and it seems to implement just what you are trying to do.

    0 讨论(0)
  • 2020-11-28 01:38

    A lot of the difficulty in implementing OAuth comes down to understanding how the authorization flow is supposed to work. This is mostly because this is the "starting point" for logging in, and when working with a third-party backend (using something like Python Social Auth) you are actually doing this twice: once for your API and once for the third-party API.

    Authorizing requests using your API and a third-party backend

    The authentication process that you need is go through is:

    Mobile App -> Your API : Authorization redirect
    Your API -> Django Login : Displays login page
    Django Login -> Facebook : User signs in
    Facebook -> Django Login : User authorizes your API
    Django Login -> Your API : User signs in
    Your API -> Mobile App : User authorizes mobile app
    

    I'm using "Facebook" as the third-party backend here, but the process is the same for any backend.

    From the perspective of your mobile app, you are only redirecting to the /authorize url provided by Django OAuth Toolkit. From there, the mobile app waits until the callback url is reached, just like in the standard OAuth authorization flow. Almost everything else (Django login, social login, etc.) is handled by either Django OAuth Toolkit or Python Social Auth in the background.

    This will also be compatible with pretty much any OAuth libraries that you use, and the authorization flow will work the same no matter what third party backend is used. It will even handle the (common) case where you need to be able to support Django's authentication backend (email/username and password) as well as a third-party login.

    Mobile App -> Your API : Authorization redirect
    Your API -> Django Login : Displays login page
    Django Login -> Your API : User signs in
    Your API -> Mobile App : User authorizes mobile app
    

    What's also important to note here is that the mobile app (which could be any OAuth client) never receives the Facebook/third-party OAuth tokens. This is incredibly important, as it makes sure your API acts as an intermediary between the OAuth client and you user's social accounts.

    Mobile App -> Your API : Authorization redirect
    Your API -> Mobile App : Receives OAuth token
    Mobile App -> Your API : Requests the display name
    Your API -> Facebook : Requests the full name
    Facebook -> Your API : Sends back the full name
    Your API -> Mobile App : Send back a display name
    

    Otherwise, the OAuth client would be able to bypass your API and make requests on your behalf to the third-party APIs.

    Mobile App -> Your API : Authorization redirect
    Your API -> Mobile App : Receives Facebook token
    Mobile App -> Facebook : Requests all of the followers
    Facebook -> Mobile App : Sends any requested data
    

    You'll notice that at this point you would have lost all control over the third-party tokens. This is especially dangerous because most tokens can access a wide range of data, which opens the door to abuse and eventually goes down under your name. Most likely, those logging into your API/website did not intend on sharing their social information with the OAuth client, and were instead expecting you to keep that information private (as much as possible), but instead you are exposing that information to everyone.

    Authenticating requests to your API

    When the mobile application then uses your OAuth token to make requests to your API, all of the authentication happens through Django OAuth Toolkit (or your OAuth provider) in the background. All you see is that there is a User associated with your request.

    Mobile App -> Your API : Sends request with OAuth token
    Your API -> Django OAuth Toolkit : Verifies the token
    Django OAuth Toolkit -> Your API : Returns the user who is authenticated
    Your API -> Mobile App : Sends requested data back
    

    This is important, because after the authorization stage it shouldn't make a difference if the user is coming from Facebook or Django's authentication system. Your API just needs a User to work with, and your OAuth provider should be able to handle the authentication and verification of the token.

    This isn't much different from how Django REST framework authenticates the user when using session-backed authentication.

    Web Browser -> Your API : Sends session cookie
    Your API -> Django : Verifies session token
    Django -> Your API : Returns session data
    Your API -> Django : Verifies the user session
    Django -> Your API : Returns the logged in user
    Your API -> Web Browser : Returns the requested data
    

    Again, all of this is handled by Django OAuth Toolkit and does not require extra work to implement.

    Working with a native SDK

    In most cases, you are going to be authenticating the user through your own website and using Python Social Auth to handle everything. But the one notable exception is when using a native SDK, as authentication and authorization is handled through the native system, which means you are bypassing your API entirely. This is great for applications which need to sign in with a third party, or applications which don't use your API at all, but it's a nightmare when both come together.

    This is because your server can't validate the login and is forced to assume that the login is valid and genuine, which means it bypasses any and all security that Python Social Auth gives you.

    Mobile App -> Facebook SDK : Opens the authorization prompt
    Facebook SDK -> Mobile App : Gets the Facebook token
    Mobile App -> Your API : Sends the Facebook token for authorization
    Your API -> Django Login : Tries to validate the token
    Django Login -> Your API : Returns a matching user
    Your API -> Mobile App : Sends back an OAuth token for the user
    

    You'll notice that this skips over your API during the authentication phase, and then forces your API to make assumptions about the token that is passed in. But there are definitely cases where this risk may be worth it, so you should evaluate that before throwing it out. It's a trade off between quick and native logins for your user and potentially handling bad or malicious tokens.

    0 讨论(0)
提交回复
热议问题