2016-07-23 40 views
3

我將僅使用Django作爲後端。前端將完成使用React和沒有Django模板。我正在使用django-rest-framework爲我的網站創建一個休息API。如何僅使用django後端並使用django-rest-framework發佈

我爲用戶做了一個序列化器。

class CustomUserSerializer(serializers.ModelSerializer): 
    class Meta: 
     model = CustomUser 
     fields = (
      'id', 'email', 'password', 'username', 'first_name', 'last_name', 'date_of_birth', 'gender', 'mobile_number' 
     ) 
     extra_kwargs = { 
      'password': {'write_only': True}, 
      'id': {'read_only': True} 
     } 

    def create(self, validated_data): 
     user = CustomUser.objects.create(
      email=validated_data['email'], 
      username=validated_data['email'], 
      first_name=validated_data['first_name'], 
      last_name=validated_data['last_name'], 
      date_of_birth=validated_data['date_of_birth'], 
      gender=validated_data['gender'], 
      mobile_number=validated_data['mobile_number'] 
     ) 
     user.set_password(validated_data['password']) 
     user.save() 
     return user 

class CustomUserViewSet(viewsets.ModelViewSet): 
    queryset = CustomUser.objects.all() 
    serializer_class = CustomUserSerializer 

在瀏覽器中,當我去/ custom/users /時,我可以查看用戶。我也可以創建新用戶,在成功註冊後返回用戶。如果我使用httpie/curl,它也可以。

(djangoweb) [email protected]:~$ http --json POST http://55.55.55.5/custom/users/ email="[email protected]" password="terminal2123" username="t223erm" first_name="te2er" last_name="mi2nal" date_of_birth=1992-12-12 gender=2 mobile_number=66222666666336 

它創建並返回新的用戶對象。

所以我做了一個表格要註冊的我不是從Django的服務器服務用戶:

<form action="http://55.55.55.5/custom/users/" method="post" id="register-form"> 
    <input type="text" placeholder="email" name="email"/> 
    ... 
    ... 
    <button id="post">Register</button> 
</form> 

和Ajax發佈形式。

// using the javscript Cookies library 
var csrftoken = Cookies.get('csrftoken'); 

function csrfSafeMethod(method) { 
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); 
} 
$.ajaxSetup({ 
    beforeSend: function(xhr, settings) { 
     if (!csrfSafeMethod(settings.type) && !this.crossDomain) { 
      xhr.setRequestHeader("X-CSRFToken", csrftoken); 
     } 
    } 
}); 

$('#post').click(function(event) { 
    event.preventDefault(); 
    var $form = $('#register-form'); 
    var data = $form.serialize();   
    $.ajax({ 
     type: "POST", 
     url: "http://55.55.55.5/custom/users/", 
     data: JSON.stringify(data), 
     sucess: function() { console.log("Success!"); }, 
     contentType: "application/json; charset=utf-8", 
     dataType: "json", 
     crossDomain:false, 
     beforeSend: function(xhr, settings) { 
      xhr.setRequestHeader("X-CSRFToken", csrftoken); 
     } 
    }); 
}); 

現在後,如果我按一下按鈕,問題開始:

  • 即使我給event.preventDefault()該頁面會自動加載到Django的服務器的URL(即http://55.55.55.5/custom/users/)。
  • 我收到一個錯誤:「detail」:「CSRF失敗:CSRF令牌丟失或不正確。」

如何使用django-rest-framework處理髮送到django服務器的帖子?我沒有找到任何有關此問題的幫助材料。你能指導我如何?謝謝。

+0

您能澄清誰在爲前端頁面提供服務嗎?是由服務器直接呈現的靜態HTML/JS,還是Django呈現它?假設它是一個靜態文件,那麼即使使用CSRF,我也不確定它是否有意義,因爲您應該使用令牌或類似的安全性。 – dkarchmer

+0

@dkarchmer是的,它是由nodejs呈現的靜態HTML/JS。我如何使用令牌如果我不是用戶呢?我認爲如果用戶進行身份驗證,就會得到令牌。你能指導我嗎?謝謝。 – Robin

回答

3

您可以使用csrf_exempt進行註冊和登錄功能。作爲一個例子,在這裏如何創建註冊和登錄API。瞭解我的登錄API如何返回令牌。見http://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication

我試圖編輯我的代碼來替換你的模型名稱,但我沒有測試它,所以你可能需要修復我有任何錯別字(或讓我知道,所以我可以修復它們)。

class AccountViewSet(viewsets.ModelViewSet): 
    queryset = CustomUser.objects.all() 
    serializer_class = CustomUserSerializer 

    def get_permissions(self): 

     if self.request.method in permissions.SAFE_METHODS: 
      return (permissions.IsAuthenticated(),) 

     if self.request.method == 'POST': 
      return (permissions.AllowAny(),) 

     return (permissions.IsAuthenticated(), IsAccountOwner(),) 

    @csrf_exempt 
    def create(self, request): 
     ''' 
     When you create an object using the serializer\'s .save() method, the 
     object\'s attributes are set literally. This means that a user registering with 
     the password \'password\' will have their password stored as \'password\'. This is bad 
     for a couple of reasons: 1) Storing passwords in plain text is a massive security 
     issue. 2) Django hashes and salts passwords before comparing them, so the user 
     wouldn\'t be able to log in using \'password\' as their password. 

     We solve this problem by overriding the .create() method for this viewset and 
     using Account.objects.create_user() to create the Account object. 
     ''' 

     serializer = self.serializer_class(data=request.data) 

     if serializer.is_valid(): 
      password = serializer.validated_data['password'] 
      confirm_password = serializer.validated_data['confirm_password'] 

      if password and confirm_password and password == confirm_password: 

       user = CustomUser.objects.create_user(**serializer.validated_data) 

       user.set_password(serializer.validated_data['password']) 
       user.save() 

       return Response(serializer.validated_data, status=status.HTTP_201_CREATED) 

     return Response({'status': 'Bad request', 
         'message': 'Account could not be created with received data.' 
         }, status=status.HTTP_400_BAD_REQUEST) 

class APILoginViewSet(APIView): 

    @csrf_exempt 
    def post(self, request, format=None): 
     data = JSONParser().parse(request) 
     serializer = LoginCustomSerializer(data=data) 

     if serializer.is_valid(): 
      email = serializer.data.get('email') 
      password = serializer.data.get('password') 

      if not request.user.is_anonymous(): 
       return Response('Already Logged-in', status=status.HTTP_403_FORBIDDEN) 

      user = authenticate(email=email, password=password) 

      if user is not None: 
       if user.is_active: 
        login(request, account) 

        serialized = UserSerializer(user) 
        data = serialized.data 

        # Add the token to the return serialization 
        try: 
         token = Token.objects.get(user=user) 
        except: 
         token = Token.objects.create(user=user) 

        data['token'] = token.key 

        return Response(data) 
       else: 
        return Response('This account is not Active.', status=status.HTTP_401_UNAUTHORIZED) 
      else: 
       return Response('Username/password combination invalid.', status=status.HTTP_401_UNAUTHORIZED) 

     return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 

    def get(self, request, format=None): 
     data_dic = {"Error":"GET not supported for this command"} 
     return Response(data_dic, status=status.HTTP_400_BAD_REQUEST) 

您可以在https://github.com/dkarchmer/django-aws-template看到一個完整的工作示例(聲明,這是我的代碼)。

希望這可以幫助您