2012-08-02 69 views
23

我試圖重寫is_authenticated在我的自定義身份驗證中。我有一個像這樣簡單的東西(先從):我如何使用tastypie登錄到django

class MyAuthentication(BasicAuthentication): 
    def __init__(self, *args, **kwargs): 
     super(MyAuthentication, self).__init__(*args, **kwargs) 

    def is_authenticated(self, request, **kwargs): 
     return True 

然後在我的ModelResource我有

class LoginUserResource(ModelResource): 

    class Meta: 
     resource_name = 'login' 
     queryset = User.objects.all() 
     excludes = ['id', 'email', 'password', 'is_staff', 'is_superuser'] 
     list_allowed_methods = ['post'] 

     authentication = MyAuthentication() 
     authorization = DjangoAuthorization() 

我不斷收到一個500錯誤回來"error_message": "column username is not unique"。我只有一個用戶名在數據庫中,它是我想要驗證的用戶。

任何想法爲什麼它會返回此錯誤?我將如何允許api客戶端登錄?

感謝您的幫助。

+0

另外,我使用的是sqlite,python 2.7和django 1.4。 – imns 2012-08-02 03:08:45

回答

69

您的方法將嘗試使用您正在進行身份驗證的用戶名創建新用戶。正如您已經注意到的那樣,這會在數據庫層出現泡沫,並且這個用戶已經存在。

你想要的是創建一個UserResource,在其上添加一個方法,用戶可以通過用戶名/密碼傳遞和登錄數據。現在

from django.contrib.auth.models import User 
from django.contrib.auth import authenticate, login, logout 
from tastypie.http import HttpUnauthorized, HttpForbidden 
from django.conf.urls import url 
from tastypie.utils import trailing_slash 

class UserResource(ModelResource): 
    class Meta: 
     queryset = User.objects.all() 
     fields = ['first_name', 'last_name', 'email'] 
     allowed_methods = ['get', 'post'] 
     resource_name = 'user' 

    def override_urls(self): 
     return [ 
      url(r"^(?P<resource_name>%s)/login%s$" % 
       (self._meta.resource_name, trailing_slash()), 
       self.wrap_view('login'), name="api_login"), 
      url(r'^(?P<resource_name>%s)/logout%s$' % 
       (self._meta.resource_name, trailing_slash()), 
       self.wrap_view('logout'), name='api_logout'), 
     ] 

    def login(self, request, **kwargs): 
     self.method_check(request, allowed=['post']) 

     data = self.deserialize(request, request.raw_post_data, format=request.META.get('CONTENT_TYPE', 'application/json')) 

     username = data.get('username', '') 
     password = data.get('password', '') 

     user = authenticate(username=username, password=password) 
     if user: 
      if user.is_active: 
       login(request, user) 
       return self.create_response(request, { 
        'success': True 
       }) 
      else: 
       return self.create_response(request, { 
        'success': False, 
        'reason': 'disabled', 
        }, HttpForbidden) 
     else: 
      return self.create_response(request, { 
       'success': False, 
       'reason': 'incorrect', 
       }, HttpUnauthorized) 

    def logout(self, request, **kwargs): 
     self.method_check(request, allowed=['get']) 
     if request.user and request.user.is_authenticated(): 
      logout(request) 
      return self.create_response(request, { 'success': True }) 
     else: 
      return self.create_response(request, { 'success': False }, HttpUnauthorized) 

你可以做發個帖子http://hostname/api/user/login數據 { 'username' : 'me', 'password' : 'l33t' }

+0

謝謝,這看起來不錯。唯一讓我困惑的是這行'PublicModelResource.Meta'。什麼是PublicModelResource? – imns 2012-08-02 13:19:53

+0

忽略它,只是從其他東西錯誤輸入。修改了答案以反映正常的元類。 – astevanovic 2012-08-02 17:46:33

+0

這種方法不會破壞一些安全問題,比如當我在/ user /上執行GET時,我將能夠看到用戶的散列密碼,並且使用正確的算法,我將能夠獲得純文本密碼。 – Milind 2012-10-23 21:25:55

1

此更新消除了GET方法的安全問題。適用於Django 1.5.4。

class UserResource(ModelResource): 

    class Meta: 
     queryset = User.objects.all() 
     resource_name = 'user' 
     allowed_methods = ['post'] 


    def prepend_urls(self): 
     return [ 
      url(r"^user/login/$", self.wrap_view('login'), name="api_login"), 
      url(r"^user/logout/$", self.wrap_view('logout'), name='api_logout'), 
     ] 

    def login(self, request, **kwargs): 
     self.method_check(request, allowed=['post']) 

     data = self.deserialize(request, request.raw_post_data, format=request.META.get('CONTENT_TYPE', 'application/json')) 

     username = data.get('username', '') 
     password = data.get('password', '') 

     user = authenticate(username=username, password=password) 
     if user: 
      if user.is_active: 
       login(request, user) 
       return self.create_response(request, { 
        'success': True 
       }) 
      else: 
       return self.create_response(request, { 
        'success': False, 
        'reason': 'disabled', 
       }, HttpForbidden) 
     else: 
      return self.create_response(request, { 
       'success': False, 
       'reason': 'incorrect', 
       }, HttpUnauthorized) 

    def logout(self, request, **kwargs): 
     self.method_check(request, allowed=['post']) 
     if request.user and request.user.is_authenticated(): 
      logout(request) 
      return self.create_response(request, { 'success': True }) 
     else: 
      return self.create_response(request, { 'success': False }, HttpUnauthorized) 
+0

來自raphodn(沒有足夠的代表評論):*關於ktsw的偉大答案的快速記錄,request.raw_post_data已棄用,您應該將request.body * – 2015-01-12 23:04:25

+1

@ktsw GET的安全問題解決了嗎?從所選答案的評論看來,這個答案似乎沒有安全問題。 「」「不,由於資源上暴露的唯一字段是fields = ['first_name','last_name','email']。此外,登錄方法只允許發佈帖子,而註銷方法只允許獲取。」「」 – 2016-03-30 08:50:05