我为什么在使用DRF和rest_framework_api_key进行POST时收到403错误?

huangapple go评论99阅读模式
英文:

Why am I getting 403 for POST with DRF and rest_framework_api_key?

问题

I am getting a 403 response from the server in my new Django app. It is very simple. I don't even have models, I just want to return an audio file, but I want to do it through an API. Because of that, since I am not going to have users, I need an API key, and I found that I can use the Django REST framework and the REST framework API key modules. I have followed the quickstarts and can't seem to get a response. It was working before, but it was authenticating through CSRF, and like I said, it is going to be an API, so I won't have CSRF cookies.

Here is the view I am using:

  1. @api_view(["POST"])
  2. def tts_view(request):
  3. data = request.POST
  4. voice_name = data.get("voice_name")
  5. text = data.get("text")
  6. if not voice_name or not text:
  7. return JsonResponse({"error": "Missing voice_name or text"}, status=400)
  8. return JsonResponse({"wav": text_to_wav(voice_name, text)}, status=200, safe=False)

The settings:

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'rest_framework',
  9. 'rest_framework_api_key',
  10. 'TTS',
  11. ]
  12. MIDDLEWARE = [
  13. 'django.middleware.security.SecurityMiddleware',
  14. 'django.contrib.sessions.middleware.SessionMiddleware',
  15. 'django.middleware.common.CommonMiddleware',
  16. 'django.middleware.csrf.CsrfViewMiddleware',
  17. 'django.contrib.auth.middleware.AuthenticationMiddleware',
  18. 'django.contrib.messages.middleware.MessageMiddleware',
  19. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
  20. ]
  21. REST_FRAMEWORK = {
  22. "DEFAULT_PERMISSION_CLASSES": [
  23. "rest_framework_api_key.permissions.HasAPIKey",
  24. ]
  25. }

And the fetch (the API key is just a test, so it doesn't matter):

  1. fetch('/create-speech', {
  2. method: 'POST',
  3. body: JSON.stringify({
  4. voice_name: "es-US-Neural2-B",
  5. text: "Estoy feliz"
  6. }),
  7. headers: {
  8. 'Authorization': '0tSMNivu.f8DOBrHTTKfMQBGANNbjl5BJQcswN9ay',
  9. 'Content-Type': 'application/json'
  10. }
  11. })
  12. .then((resp) => {
  13. if (!resp.ok) throw Error(`${resp.statusText} - ${resp.status}`);
  14. return resp.json();
  15. })
  16. .then((wav) => {
  17. console.log('success');
  18. });

I am doing the fetch in the console on the default page, which is not defined (like I said, I only want an API).

I have tried including rest_framework.permissions.AllowAny into DEFAULT_PERMISSION_CLASSES, but it doesn't work either.

I don't really know what else to do, so any help would be appreciated. Thanks!

英文:

I am getting a 403 response from the server in my new Django app. It is very simple. I don't even have models, I just want to return an audio file, but I want to do it through an API. Because of that, since I am not going to have users, I need an API key, and I found that I can use the Django REST framework and the REST framework API key modules. I have followed the quickstarts and can't seem to get a response. It was working before, but it was authenticating through CSRF, and like I said, it is going to be an API, so I won't have CSRF cookies.

Here is the view I am using:

  1. @api_view(["POST"])
  2. def tts_view(request):
  3. data = request.POST
  4. voice_name = data.get("voice_name")
  5. text = data.get("text")
  6. if not voice_name or not text:
  7. return JsonResponse({"error": "Missing voice_name or text"}, status=400)
  8. return JsonResponse({"wav": text_to_wav(voice_name, text)}, status=200, safe=False)

The settings:

  1. INSTALLED_APPS = [
  2. 'django.contrib.admin',
  3. 'django.contrib.auth',
  4. 'django.contrib.contenttypes',
  5. 'django.contrib.sessions',
  6. 'django.contrib.messages',
  7. 'django.contrib.staticfiles',
  8. 'rest_framework',
  9. 'rest_framework_api_key',
  10. 'TTS',
  11. ]
  12. MIDDLEWARE = [
  13. 'django.middleware.security.SecurityMiddleware',
  14. 'django.contrib.sessions.middleware.SessionMiddleware',
  15. 'django.middleware.common.CommonMiddleware',
  16. 'django.middleware.csrf.CsrfViewMiddleware',
  17. 'django.contrib.auth.middleware.AuthenticationMiddleware',
  18. 'django.contrib.messages.middleware.MessageMiddleware',
  19. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
  20. ]
  21. REST_FRAMEWORK = {
  22. "DEFAULT_PERMISSION_CLASSES": [
  23. "rest_framework_api_key.permissions.HasAPIKey",
  24. ]
  25. }

And the fetch (the API key is just a test, so it doesn't matter):

  1. fetch('/create-speech', {
  2. method: 'POST',
  3. body: JSON.stringify({
  4. voice_name: "es-US-Neural2-B",
  5. text: "Estoy feliz"
  6. }),
  7. headers: {
  8. 'Authorization': '0tSMNivu.f8DOBrHTTKfMQBGANNbjl5BJQcswN9ay',
  9. 'Content-Type': 'application/json'
  10. }
  11. })
  12. .then((resp) => {
  13. if (!resp.ok) throw Error(`${resp.statusText} - ${resp.status}`);
  14. return resp.json();
  15. })
  16. .then((wav) => {
  17. console.log('success');
  18. });

I am doing the fetch in the console on the default page, which is not defined (like I said, I only want an API).

I have tried including rest_framework.permissions.AllowAny into DEFAULT_PERMISSION_CLASSES, but it doesn't work either.

I don't really know what else to do, so any help would be appreciated. Thanks!

答案1

得分: 1

来自Django REST Framework API Key文档

默认情况下,客户端必须通过Authorization头传递其API密钥。它必须按照以下格式进行格式化:

Authorization: Api-Key <API_KEY>

你漏掉了Api-Key 部分(注意它与<API_KEY>部分之间的空格)。因此,你的请求应该是:

  1. fetch('/create-speech', {
  2. ...
  3. headers: {
  4. 'Authorization': 'Api-Key 0tSMNivu.f8DOBrHTTKfMQBGANNbjl5BJQcswN9ay',
  5. 'Content-Type': 'application/json'
  6. }
  7. })
  8. ...
英文:

From the Django REST Framework API Key docs:

> By default, clients must pass their API key via the Authorization header. It must be formatted as follows:
>
> Authorization: Api-Key &lt;API_KEY&gt;

You're missing the Api-Key part (notice the space between it and the &lt;API_KEY&gt; part). So your request should be:

  1. fetch(&#39;/create-speech&#39;, {
  2. ...
  3. headers: {
  4. &#39;Authorization&#39;: &#39;Api-Key 0tSMNivu.f8DOBrHTTKfMQBGANNbjl5BJQcswN9ay&#39;,
  5. &#39;Content-Type&#39;: &#39;application/json&#39;
  6. }
  7. })
  8. ...

答案2

得分: 0

你应该添加一个CSRF例外权限类或装饰器,例如:

from django.views.decorators.csrf import csrf_exempt

并且在你的API视图声明之前添加:

  1. @api_view(["POST"])
  2. @csrf_exempt
  3. def tts_view(request):

有了这个,只要在API调用的标头中传递您的DRF API令牌,如下所示:

Authorization: Token token_string

就应该足够了。

英文:

You should add a CSRF exemption permission class or decorator, e.g.:

from django.views.decorators.csrf import csrf_exempt

and above your API view declaration:

  1. @api_view([&quot;POST&quot;])
  2. @csrf_exempt
  3. def tts_view(request):

With this, ensuring that you pass in your DRF API token in headers in your API call as
Authorization: Token token_string
should suffice.

huangapple
  • 本文由 发表于 2023年4月20日 01:46:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76057447.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定