2015-04-05 14 views
8

Tôi đang sử dụng Bộ công cụ xã hội Python và Bộ công cụ Django OAuth để quản lý tài khoản người dùng của mình và hạn chế quyền truy cập vào API REST của tôi.Tạo mã thông báo truy cập theo lập trình với Bộ công cụ Django OAuth2

tôi có thể tạo ra một mã thông báo cho người dùng rằng đăng ký bằng tay với ứng dụng của tôi bằng cách sử dụng thường xuyên

curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://localhost:8000/o/token/

Nhưng khi tôi đăng ký người dùng của tôi với PSA bằng thẻ truy cập của họ, tôi muốn tạo mã thông báo Bộ công cụ OAuth2 cho ứng dụng của riêng tôi và trả lại nó dưới dạng JSON cho ứng dụng để nó có thể sử dụng nó để tạo yêu cầu với API của tôi.

Hiện tại, tôi tạo mã thông báo chỉ cần sử dụng generate_token từ oauthlib, đó là thực tiễn tốt? Tôi có nên xem xét các yếu tố khác không?

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. 
    token = request.GET.get('access_token') 
    user = request.backend.do_auth(token) 

    if user: 
     login(request, user) 
     app = Application.objects.get(name="myapp") 

     # We delete the old one 
     try: 
      old = AccessToken.objects.get(user=user, application=app) 
     except: 
      pass 
     else: 
      old.delete() 

     # We create a new one 
     tok = generate_token() 

     AccessToken.objects.get_or_create(user=user, 
              application=app, 
              expires=now() + timedelta(days=365), 
              token=tok) 

     return "OK" # I will eventually return JSON with the token 
    else: 
     return "ERROR" 
+0

Câu hỏi thực sự thú vị. Tôi không tìm thấy bất kỳ câu trả lời hữu ích khác để I0m làm việc dựa trên bài đăng blog của bạn – vabada

+2

Tôi đề nghị bạn hãy xem https://github.com/PhilipGarnero/django-rest-framework-social-oauth2 giúp bạn làm chính xác điều này một cách sạch sẽ. –

Trả lời

0

Gần đây tôi đã sử dụng https://github.com/PhilipGarnero/django-rest-framework-social-oauth2 cho mục đích này như người dùng Felix D. được đề xuất. Bên dưới là triển khai của tôi:

class TokenHandler: 
application = Application.objects.filter(name=APPLICATION_NAME).values('client_id', 'client_secret') 

def handle_token(self, request): 
    """ 
    Gets the latest token (to access my API) and if it's expired, check to see if the social token has expired. 
    If the social token has expired, then the user must log back in to access the API. If it hasn't expired, 
    (my) token is refreshed. 
    """ 
    try: 
     token_list = AccessToken.objects.filter(user=request.user)\ 
      .order_by('-id').values('token', 'expires') 
     if token_list[0]['expires'] < datetime.now(timezone.utc): 
      if not self.social_token_is_expired(request): 
       token = self.refresh_token(request) 
      else: 
       token = 'no_valid_token' 
     else: 
      token = token_list[0]['token'] 
    except IndexError: # happens where there are no old tokens to check 
     token = self.convert_social_token(request) 
    except TypeError: # happens when an anonymous user attempts to get a token for the API 

     token = 'no_valid_token' 
    return token 

def convert_social_token(self, request): 
    grant_type = 'convert_token' 
    client_id = self.application[0]['client_id'] 
    client_secret = self.application[0]['client_secret'] 
    try: 
     user_social_auth = request.user.social_auth.filter(user=request.user).values('provider', 'extra_data')[0] 
     backend = user_social_auth['provider'] 
     token = user_social_auth['extra_data']['access_token'] 
     url = get_base_url(request) + reverse('convert_token') 
     fields = {'client_id': client_id, 'client_secret': client_secret, 'grant_type': grant_type, 
        'backend': backend, 
        'token': token} 
     if backend == 'azuread-oauth2': 
      fields['id_token'] = user_social_auth['extra_data']['id_token'] 
     response = requests.post(url, data=fields) 
     response_dict = json.loads(response.text) 
    except IndexError: 
     return {'error': 'You must use an OAuth account to access the API.'} 
    except UserSocialAuth.DoesNotExist: 
     return {'error': 'You must use an OAuth account to access the API.'} 
    return response_dict['access_token'] 

def refresh_token(self, request): 
    grant_type = 'refresh_token' 
    client_id = self.application[0]['client_id'] 
    client_secret = self.application[0]['client_secret'] 
    try: 
     refresh_token_object = RefreshToken.objects.filter(user=request.user).order_by('-id').values('token')[0] 
     token = refresh_token_object['token'] 
     url = get_base_url(request) + reverse('token') 
     fields = {'client_id': client_id, 'client_secret': client_secret, 'grant_type': grant_type, 
        'refresh_token': token} 
     response = requests.post(url, data=fields) 
     response_dict = json.loads(response.text) 
    except RefreshToken.DoesNotExist: 
     return {'error': 'You must use an OAuth account to access the API.'} 

    return response_dict['access_token'] 

@staticmethod 
def social_token_is_expired(request): 
    user_social_auth = UserSocialAuth.objects.filter(user=request.user).values('provider', 'extra_data')[0] 
    try: 
     return float(user_social_auth['extra_data']['expires_on']) <= datetime.now().timestamp() 
    except KeyError: # social API did not provide an expiration 
     return True # if our token is expired and social API did not provide a time, we do consider them expired 
Các vấn đề liên quan