2

我使用ember-simple-authember-simple-auth-token允許用戶登錄到我的應用程序發帖時(不能接受)。但是,當我通過POST請求使用用戶名和密碼進行身份驗證來調用後端的Django Rest Framework時,出現406(不可接受)錯誤。這在DRF可瀏覽的API中不會發生,所以後端似乎工作正常。406從灰燼到DRF API

我懷疑有關CORS的東西。我在Django中使用django-cors-headers,並允許在我的開發環境中使用。如果有問題,我也使用django-rest-framework-jwtdjango-rest-framework-json-api包。

我的API顯示了一個選項,然後按所發的帖子電話:

[09/Mar/2016 07:15:54] "OPTIONS /api-token-auth/ HTTP/1.1" 200 0 
[09/Mar/2016 07:15:54] "POST /api-token-auth/ HTTP/1.1" 406 114 

響應頭:

HTTP/1.0 406 Not Acceptable 
Date: Wed, 09 Mar 2016 07:15:54 GMT 
Server: WSGIServer/0.2 CPython/3.5.1 
X-Frame-Options: SAMEORIGIN 
Access-Control-Allow-Origin: * 
Content-Type: application/vnd.api+json 
Allow: POST, OPTIONS 
Vary: Accept 

請求頭:

POST /api-token-auth/ HTTP/1.1 
Host: localhost:8000 
Connection: keep-alive 
Content-Length: 2 
Accept: application/json, text/javascript 
Origin: http://localhost:4200 
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/48.0.2564.116 Chrome/48.0.2564.116 Safari/537.36 
Content-Type: application/json 
Referer: http://localhost:4200/login 
Accept-Encoding: gzip, deflate 
Accept-Language: en-US,en;q=0.8 

請求頭不顯示代替application/vnd.api+json,但代替application/json。不幸的是,無論我在Ember做什麼都能解決這個問題。我沒有成功地嘗試將我的應用的JSONAPIAdapter的標頭設置爲"Accept": "application/vnd.api+json",並在ENV['ember-simple-auth-token']中嘗試設置標頭。

+0

我認爲我聽說默認情況下,ember和DRF不兼容。你使用的是像https://github.com/dustinfarris/ember-django-adapter之類的東西嗎? – ilse2005

+0

@ ilse2005,我正在使用'django-rest-framework-json-api'來使DRF響應與JSON API規範兼容。 –

回答

1

我設法解決這個問題,或多或少。這是一個不幸的軟件包組合,導致在Ember和DRF之間使用JSON API規範時出現一些問題。

首先,通過簡單地將標頭作爲參數添加到.authenticate,我在controllers/login.js中設法執行的標頭覆蓋。任何參數都會傳遞給ember-simple-auth驗證器。 (我並不需要實現我自己的認證,如帕沃爾在他的回答引起的)

// controllers/login.js 
import Ember from 'ember'; 

export default Ember.Controller.extend({ 
    session: Ember.inject.service('session'), 

    actions: { 
    authenticate: function() { 
     var credentials = this.getProperties('identification', 'password'), 
     authenticator = 'authenticator:jwt', 
     // Set headers to accept JSON API format 
     headers = { 
      'Accept': 'application/vnd.api+json', 
      'Content-Type': 'application/vnd.api+json' 
     }; 

     this.get('session').authenticate(authenticator, credentials, headers); 
    } 
    } 
}); 

此介紹了下一個問題:我的內容類型實際上並沒有JSON API規範,所以我也需要實現我自己身份驗證器來翻譯ember-simple-auth-token的JWT身份驗證器以生成JSON API規範兼容格式。沒有得到它的工作,但這樣的事情:現在

// authenticators/jwt.js 
import Base from 'ember-simple-auth-token/authenticators/token'; 

export default Base.extend({ 
    /** 
    Returns an object used to be sent for authentication. 

    @method getAuthenticateData 
    @return {object} An object with properties for authentication. 
    */ 
    // Make sure this is JSON API compatible format. 
    getAuthenticateData(credentials) { 
    const authentication = { 
     // This is apparently not valid JSON API spec, but you get the gist... 
     'data': [{ 
     [this.identificationField]: credentials.identification, 
     [this.passwordField]: credentials.password 
     }] 
    }; 

    return authentication; 
    } 
}); 

,在後端,rest_framework_jwtrest_framework_json_api仍然打得不好在一起。

此時,我決定放棄對認證端點的JSON API規範的需求簡單得多:Ember的包沒有生成它,而且DRF在解析它時遇到了麻煩!

所以,我將Ember方面的所有東西都還原了,讓它根據我原來的問題產生請求。在DRF的一面,我子類rest_framework_jwt的意見,並設置解析器DRF的默認JSONParser

""" 
Make the JWT Views ignore JSON API package and use standard JSON. 
""" 

from rest_framework_jwt.views import ObtainJSONWebToken, RefreshJSONWebToken, \ 
    VerifyJSONWebToken 
from rest_framework.parsers import JSONParser 
from rest_framework.renderers import JSONRenderer 


class ObtainJSONWebTokenPlainJSON(ObtainJSONWebToken): 
    parser_classes = (JSONParser,) 
    renderer_classes = (JSONRenderer,) 


class RefreshJSONWebTokenPlainJSON(RefreshJSONWebToken): 
    parser_classes = (JSONParser,) 
    renderer_classes = (JSONRenderer,) 


class VerifyJSONWebTokenPlainJSON(VerifyJSONWebToken): 
    parser_classes = (JSONParser,) 
    renderer_classes = (JSONRenderer,) 

最終結果:通過讓我跟着API JSON API規範,除了隨處可見的令牌認證端點解決。

+1

FWI,我能夠通過確保'rest_framework.parsers.JSONParser'同時獲得JSON API和正常的JSON請求(並因此認證)和'rest_framework_json_api.parsers.JSONParser'包含在'DEFAULT_PARSER_CLASSES'中用於DRF的設置以及'DEFAULT_RENDERER_CLASSES'設置中的'rest_framework_json_api.renderers.JSONRenderer'和'rest_framework.renderers.JSONRenderer',這也是TimmyO'Mahony的 –

+0

,也爲我工作。謝謝,它使我的代碼更加簡潔。 –

0

你應該能夠明確設置內容類型的適配器:

export default DS.JSONAPIAdapter.extend({ 
// set content-type upon every ajax request 
ajax: function(url, type, hash){ 
hash = hash || {} ; 
hash.headers = hash.headers || {}; 
hash.headers['Content-Type'] = 'application/vnd.api+json'; 
return this._super(url, type, hash); 
} 
}); 

它是否解決問題了嗎?

+0

不,同樣的問題。 –

+0

您是否可以確認您的請求是否在頭文件的content-type字段中使用了'application/vnd.api + json'而不是'application/json'? – Pavol

+0

它沒有。如果是這樣,那可能解決我的問題。 –

1

實現自己的認證,其設置身份驗證請求過程中使用的標題:

// your-app/authenticators/your-custom-authenticator.js 
import OAuth2PasswordGrant from 'ember-simple-auth/authenticators/oauth2-password-grant'; 

export default OAuth2PasswordGrant.extend({ 

    /** 
    * your backend authentication endpoint 
    * @overrides 
    */ 
    serverTokenEndpoint: `https://your.authentication.endpoint.sth/login`, 

    /** 
    * Makes a request to the authentication server. 
    * This is what you need to override to customize your headers 
    * set up for purposes of authentication. 
    * @overrides 
    */ 
    makeRequest(url, data) { 
    const options = { 
     url: url, 
     data: data, 
     type: 'GET', 
     dataType: 'json', 
     accept: 'application/vnd.api+json', 
     headers: { 
     "Content-Type": 'application/vnd.api+json' 
     } 
    }; 

    return Ember.$.ajax(options); 
    } 
}); 

請參閱本定製的認證在你(登錄)路線/控制器/無論你需要:

this.get('session').authenticate('authenticator:yourCustomAuthenticator', username, password).then(() => { 
      // success, redirect, as you like.. 
     }) 

取查看一下ember-simple-auth文檔的Authenticators部分,以根據需要選擇一個父驗證器:ember-simple-auth - Authenticators