2016-07-23 2 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 

Он создает и возвращает новый объект пользователя.

Так что я сделал форму для регистрации пользователя, который я не служу с сервера Джанго:

<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> 

И Аякса, чтобы отправить форму.

// 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() страница автоматически загружается в URL сервера Джанго (т.е. http://55.55.55.5/custom/users/).
  • Я получаю сообщение об ошибке: «detail»: «CSRF Failed: токен CSRF отсутствует или неверен».

Как я могу обработать сообщение на сервере django, используя django-rest-framework? Я не нашел ничего полезного для этой проблемы. Не могли бы вы посоветовать мне, как это сделать? Спасибо.

+0

Уточните, кому отводится внешняя страница? Является ли статический HTML/JS, непосредственно отображаемый сервером, или Django рендеринга? Предполагая, что это статический файл, я не уверен, что имеет смысл даже использовать CSRF, так как вы, вероятно, должны использовать маркер или аналогичный для безопасности. – dkarchmer

+0

@dkarchmer Да, это статический HTML/JS, полученный от nodejs. Как я могу использовать токен, если я еще не пользователь? Я думал, что токены выдаются, если пользователь аутентифицируется. Не могли бы вы направить меня. Спасибо. – 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 (оговорке, что мой код).

Надеюсь, это вам поможет