2017-06-19 172 views
0

我正在使用Django REST开发API。客户端是在node.js中运行的AngularJS中的SPA。注册并登录做工精细,但是当用户执行退出的错误消息表明:未提供Angular + Django REST身份验证凭证

{“细节”:“不提供身份验证凭据”}

我试过很多解决方案,如post 1post 2。但问题仍在继续。如果我的Angular文件在服务器中,我的页面可以正常工作,但是当我更改由yeoman创建的SPA时,我遇到了证书问题。

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/.*$' 

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 

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) 

在我的Angul AR应用,app.js

app.run(run); 

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

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

我得到令牌码登录后:

$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 !!!'); 
} 

注销

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 !!!'); 
} 

回答

0

从您的DRF DEFAULT_AUTHENTICATION_CLASSES删除'rest_framework.authentication.SessionAuthentication',只使用TokenAuth,如果你仍然需要可浏览的api,你可以使用chrome插件n ModHeader

0

我发现了这个问题。我没有正确地将标记添加到标头。

我得到令牌和存储在本地存储。

$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 !!!'); 
} 

当应用程序(页)开始,我加载从本地存储的令牌app.js:

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


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

感谢YKH的帮助。