2017-06-19 1 views
0

Je développe une API avec Django REST. Le client est un SPA dans AngularJS s'exécutant dans node.js. Inscrivez-vous et à l'identification fonctionne très bien, mais lorsque l'utilisateur fait déconnecter le message d'erreur est montré:Angular + Django REST Les informations d'identification de l'authentification n'ont pas été fournies

{ « détail »: «informations d'identification d'authentification ne sont pas fournis »}

J'ai essayé plusieurs solutions, comme post 1 et post 2. mais le problème continue. Si mes fichiers Angular sont dans le serveur, ma page fonctionne bien, mais quand j'ai changé pour un SPA créé par yeoman, j'ai le problème des identifiants.

Mon settings.py

import os 

# Build paths inside the project like this: os.path.join(BASE_DIR, ...) 
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 


# Quick-start development settings - unsuitable for production 
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/ 

# SECURITY WARNING: keep the secret key used in production secret! 
SECRET_KEY = 'y6u0gy4ij&[email protected]*[email protected])@)(l!-j&wmpot4h#' 

# SECURITY WARNING: don't run with debug turned on in production! 
DEBUG = True 

ALLOWED_HOSTS = [] 


# Application definition 

INSTALLED_APPS = [ 
    'django.contrib.admin', 
    'django.contrib.auth', 
    'django.contrib.contenttypes', 
    'django.contrib.sessions', 
    'django.contrib.messages', 
    'django.contrib.staticfiles', 

    'rest_framework', 
    'rest_framework.authtoken', 
    'authentication', 
    'corsheaders', 
] 

MIDDLEWARE = [ 
    'django.middleware.security.SecurityMiddleware', 
    'django.contrib.sessions.middleware.SessionMiddleware', 
    'corsheaders.middleware.CorsMiddleware', 
    'django.middleware.common.CommonMiddleware', 
    'django.middleware.csrf.CsrfViewMiddleware', 
    'django.contrib.auth.middleware.AuthenticationMiddleware', 
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware', # 
    'django.contrib.messages.middleware.MessageMiddleware', 
    'django.middleware.clickjacking.XFrameOptionsMiddleware', 
] 

ROOT_URLCONF = 'ServerLearn.urls' 

TEMPLATES = [ 
    { 
     'BACKEND': 'django.template.backends.django.DjangoTemplates', 
     'DIRS': [], 
     'APP_DIRS': True, 
     'OPTIONS': { 
      'context_processors': [ 
       'django.template.context_processors.debug', 
       'django.template.context_processors.request', 
       'django.contrib.auth.context_processors.auth', 
       'django.contrib.messages.context_processors.messages', 
      ], 
     }, 
    }, 
] 


REST_FRAMEWORK = { 
    'DEFAULT_PERMISSION_CLASSES': (
     'rest_framework.permissions.IsAuthenticated', 
    ), 

    'DEFAULT_AUTHENTICATION_CLASSES': (
     'rest_framework.authentication.SessionAuthentication', 
     'rest_framework.authentication.TokenAuthentication', 
    ) 
} 


WSGI_APPLICATION = 'ServerLearn.wsgi.application' 


# Database 
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases 

DATABASES = { 
    'default': { 
     'ENGINE': 'django.db.backends.sqlite3', 
     'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 
    } 
} 


# Password validation 
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators 

AUTH_PASSWORD_VALIDATORS = [ 
    { 
     'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', 
    }, 
    { 
     'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', 
    }, 
    { 
     'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', 
    }, 
    { 
     'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', 
    }, 
] 


# Internationalization 
# https://docs.djangoproject.com/en/1.11/topics/i18n/ 

LANGUAGE_CODE = 'en-us' 

TIME_ZONE = 'UTC' 

USE_I18N = True 

USE_L10N = True 

USE_TZ = True 


# Static files (CSS, JavaScript, Images) 
# https://docs.djangoproject.com/en/1.11/howto/static-files/ 

STATIC_URL = '/static/' 

AUTH_USER_MODEL = 'authentication.Account' 

CORS_ORIGIN_ALLOW_ALL = True 
CORS_URLS_REGEX = r'^/api/v1/.*$' 

Mon models.py

from django.contrib.auth.models import AbstractBaseUser, BaseUserManager 
from django.db import models 

from django.db.models.signals import post_save 
from django.dispatch import receiver 
from rest_framework.authtoken.models import Token 
from django.conf import settings 

# Create your models here. 

@receiver(post_save, sender=settings.AUTH_USER_MODEL) 
def create_auth_token(sender, instance=None, created=False, **kwargs): 
    if created: 
     token = Token.objects.create(user=instance) 
     print(token) 


class AccountManager(BaseUserManager): 
    def create_user(self, username, password=None, **kwargs): 
     if not username: 
      raise ValueError("Need username.") 

     if not kwargs.get("email"): 
      raise ValueError("Need email.") 

     account = self.model(
      username = username, 
      email = self.normalize_email(kwargs.get("email")), 
      name = kwargs.get("name"), 
      age = kwargs.get("age"), 
      gender = kwargs.get("gender"), 
      #birth = kwargs.get("birth") 
     ) 

     account.set_password(password) 
     account.save() 

     return account 

    #admin 
    #senhaadmin 
    def create_superuser(self, username, password, **kwargs): 
     account = self.model(
      username = username, 
      email = self.normalize_email(kwargs.get("email")), 
      name = "Admin", 
      age = 31111, 
      gender = 555, 
     ) 

     account.is_admin = True 
     account.set_password(password) 
     account.save() 

     return account 



class Account(AbstractBaseUser): 
    username = models.CharField(max_length = 50, unique = True) 
    email = models.EmailField(unique = True) 
    name = models.CharField(max_length = 100) 
    age = models.PositiveSmallIntegerField() 
    gender = models.PositiveSmallIntegerField() 
    #birth = models.DateField(null = True, blank = True) 
    created_at = models.DateTimeField(auto_now_add = True) 
    updated_at = models.DateTimeField(auto_now = True) 
    is_admin = models.BooleanField(default = False) 

    objects = AccountManager() 

    USERNAME_FIELD = 'username' 
    REQUIRED_FILES = ['username', 'email', 'name', 'age', 'gender'] 

    def __unicode__ (self): 
     return self.username 

Mon views.py

class AccountViewSet(viewsets.ModelViewSet): 
    lookup_field = 'username' 
    queryset = Account.objects.all() 
    serializer_class = AccountSerializer 

    def get_permissions(self): 
     if self.request.method in permissions.SAFE_METHODS: 
      return (permissions.AllowAny(),) 

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

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

    def create(self, request): 
     serializer = self.serializer_class(data = request.data) 

     if serializer.is_valid(): 
      Account.objects.create_user(**serializer.validated_data) 

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

     return Response({ 
      'status': 'Bad request', 
      'message': 'Conta não pode ser criada' 
      }, status = status.HTTP_400_BAD_REQUEST) 


class LoginView(views.APIView): 
    def post(self, request, format=None): 
     data = json.loads(request.body.decode('utf-8')) 

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

     account = authenticate(username=username, password=password) 

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

       serialized = AccountSerializer(account) 

       return Response(serialized.data) 
      else: 
       return Response({ 
        'status': 'Unauthorized', 
        'message': 'This account has been disabled.' 
       }, status=status.HTTP_401_UNAUTHORIZED) 
     else: 
      return Response({ 
       'status': 'Unauthorized', 
       'message': 'Username/password combination invalid.' 
      }, status=status.HTTP_401_UNAUTHORIZED) 


class LogoutView(views.APIView): 

    #ERROR IN NEXT LINE 
    permission_classes = (permissions.IsAuthenticated,) 

    def post(self, request, format=None): 

     logout(request) 
     return Response({}, status=status.HTTP_204_NO_CONTENT) 

Dans mon Angul application ar, dans app.js

app.run(run); 

run.$inject = ['$http']; 

function run($http) { 
     $http.defaults.xsrfHeaderName = 'X-CSRFToken'; 
     $http.defaults.xsrfCookieName = 'csrftoken'; 
} 

je suis jeton après la connexion avec le code:

$http.post('http://localhost:8000/api/v1/api-token-auth/', { 
    username: username, 
    password: password 
}).then(tokenSuccessFn, tokenErrorFn); 

function tokenSuccessFn(data, status, headers, config) { 
    console.log("token: "); 
    console.log(JSON.stringify(data)); 
    $http.defaults.headers.common.Authorization = 'Token ' + $cookies.get("csrftoken");     
} 

function tokenErrorFn(data, status, headers, config) { 
    console.error('token error !!!'); 
} 

Le est fermeture de session

return $http.post('http://localhost:8000/api/v1/auth/logout/') 
    .then(logoutSuccessFn, logoutErrorFn); 

function logoutSuccessFn(data, status, headers, config) { 
    Authentication.unauthenticate(); 

    window.location = '/'; 
} 

function logoutErrorFn(data, status, headers, config) { 
    console.error('Logout error !!!'); 
} 

Répondre

0

enlever 'rest_framework.authentication.SessionAuthentication' de votre DRF DEFAULT_AUTHENTICATION_CLASSES, utilisez uniquement TokenAuth, si vous avez encore besoin d'API, vous pouvez utiliser des plugins chrome n ModHeader.

0

J'ai trouvé le problème. Je n'ai pas ajouté le jeton à l'en-tête correctement. Je reçois le jeton et le stockage dans un stockage local.

$http.post('http://localhost:8000/api/v1/api-token-auth/', { 
    username: username, 
    password: password 
}).then(tokenSuccessFn, tokenErrorFn); 

function tokenSuccessFn(data, status, headers, config) { 

    localStorage.setItem('myApp.token',data['data'].token); 
} 

function tokenErrorFn(data, status, headers, config) { 
    console.error('token error !!!'); 
} 

Lorsque l'application (page) commence, je charge le jeton de stockage local dans app.js:

app.run(['$http', function ($http) { 


    $http.defaults.headers.common['Authorization'] = 'Token ' + localStorage.getItem('myApp.token');   
}]); 

Merci YKH pour l'aide.