Rails API ActiveStorage DirectUpload производит 422 Ошибка InvalidAuthenticityToken - PullRequest
0 голосов
/ 10 мая 2019

У меня проблема с активным хранилищем приложения Rails API. У меня есть React, откуда я хочу загрузить файл.

import React from "react";
import {DirectUpload} from "activestorage";

class SignIn extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      file: null
    };
    this.handleFileChange = this.handleFileChange.bind(this);
    this.handleFileSubmit = this.handleFileSubmit.bind(this);
  }

  handleFileChange(e){
    this.setState({file: e.target.files[0]})
  }

  handleFileSubmit(){
    const upload = new DirectUpload(this.state.file, "/rails/active_storage/direct_uploads");

    upload.create((error, blob) => {
      if(error){
        console.log(error)
      } else {
        console.log(blob)
      }
    })
  }

  render() {

    return (
      <React.Fragment>
          <Form>
          <Form.Item>
            <Input type="file" onChange={this.handleFileChange}/>
          </Form.Item>

          <Form.Item>
            <Button type="primary" htmlType="submit">
              Register
            </Button>
          </Form.Item>
        </Form>
      </React.Fragment>
    );
  }
}

Но при отправке я получил ошибку Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms)

Started POST "/rails/active_storage/direct_uploads" for 127.0.0.1 at 2019-05-09 22:59:54 +0200
Processing by ActiveStorage::DirectUploadsController#create as JSON
  Parameters: {"blob"=>{"filename"=>"file.jpg", "content_type"=>"image/jpeg", "byte_size"=>27095, "checksum"=>"8u95dXg39vap1Cq/2fgfbg=="}, "direct_upload"=>{"blob"=>{"filename"=>"file.jpg", "content_type"=>"image/jpeg", "byte_size"=>27095, "checksum"=>"8u95dXg39vap1Cq/2fgfbg=="}}}
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms)



ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):

actionpack (5.2.3) lib/action_controller/metal/request_forgery_protection.rb:211:in `handle_unverified_request'
actionpack (5.2.3) lib/action_controller/metal/request_forgery_protection.rb:243:in `handle_unverified_request'
devise (4.6.2) lib/devise/controllers/helpers.rb:255:in `handle_unverified_request'
actionpack (5.2.3) lib/action_controller/metal/request_forgery_protection.rb:238:in `verify_authenticity_token'
activesupport (5.2.3) lib/active_support/callbacks.rb:426:in `block in make_lambda'
activesupport (5.2.3) lib/active_support/callbacks.rb:198:in `block (2 levels) in halting'
actionpack (5.2.3) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
activesupport (5.2.3) lib/active_support/callbacks.rb:199:in `block in halting'
activesupport (5.2.3) lib/active_support/callbacks.rb:513:in `block in invoke_before'

Я установил в application_controller.rb protect_from_forgery with: :null_session, но я все еще получил ошибку.

1 Ответ

0 голосов
/ 17 мая 2019

У меня была такая же проблема. Два способа решить эту проблему:

1. Пластырь обезьяны (не рекомендуется)

в config/initializers/direct_uploads.rb:

require 'active_storage/direct_uploads_controller'

class ActiveStorage::DirectUploadsController
  protect_from_forgery with: :null_session
end

2. Пользовательский контроллер (рекомендуется)

Допустим, у вас есть и конечная точка API для /api/v1:

config/routes.rb

namespace :api do
  scope module: 'v1', path: 'v1' do
    resources :direct_uploads, only: [:create]
  end
end

app/controllers/api/v1/direct_uploads_controller.rb

class Api::V1::DirectUploadsController < ActiveStorage::DirectUploadsController
  # Should only allow null_session in API context, so request is JSON format
  protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }

  # Also, since authenticity verification by cookie is disabled, you should implement you own logic :
  before_action :verify_user

  private

  def verify_user
    raise unless User.find(doorkeeper_token[:resource_owner_id])
  end
end

И измените экземпляр DirectUpload с правильной конечной точкой:

const upload = new DirectUpload(this.state.file, "/api/v1/direct_uploads");

Надеюсь, это поможет. Ура!

...