简体   繁体   English

Devise-JWT:使用 cURL 我可以看到一个 Authorization 标头。 使用 Axios/Fetch 没有 Authorization 头

[英]Devise-JWT: Using cURL I can see an Authorization header. Using Axios/Fetch there is no Authorization header

I have a very typical Rails backend with Devise and Devise-JWT.我有一个非常典型的 Rails 后端,带有 Devise 和 Devise-JWT。 When I make a raw cURL request to the endpoint /users/sign_in I can see in the headers that it is setting an Authorization header with a token.当我向端点/users/sign_in发出原始 cURL 请求时,我可以在标头中看到它正在使用令牌设置授权标头。

When I do the same request on my React frontend (which is on a different port, so cross origin configuration is necessary) the only headers I'm seeing in the result are cache-control and content-type.当我在我的 React 前端(位于不同的端口上,因此需要跨源配置)执行相同的请求时,我在结果中看到的唯一标头是缓存控制和内容类型。

Now, I have installed the 'cors' gem.现在,我已经安装了 'cors' gem。 I have created an initializer called config/initializers/cors.rb and I have put this configuration inside:我创建了一个名为config/initializers/cors.rb ,并将此配置放入其中:

Rails.application.config.middleware.insert_before 0, Rack::Cors do
    allow do
        origins '*'
        resource('*',
            headers: :any,
            expose: ["Authorization"],
            methods: :any
        )
    end
end

Yet when I make the request in my React frontend, I see no Authorization header.然而,当我在 React 前端发出请求时,我看不到 Authorization 标头。

I can see that Rails is responding with a 302 redirect.我可以看到 Rails 正在响应 302 重定向。 Is this part of the problem?这是问题的一部分吗? Do I need to configure devise to stop responding with a 302?我是否需要配置设备以停止响应 302?

I am utterly lost as to what the problem could be.我完全不知道问题可能是什么。

If you observe the screenshot that follows, logging in the normal way via plain form login gives me an Authorization header, but if I do it via AJAX there is no header.如果您观察下面的屏幕截图,通过普通表单登录以正常方式登录会给我一个 Authorization 标头,但如果我通过 AJAX 进行登录,则没有标头。

此图显示使用非 AJAX 请求正常访问 /users/sign_in 端点时有一个 Authorization 标头

This is the frontend (AJAX) code which doesn't give me any Authorization header, only "cache-control" and "content-type":这是前端 (AJAX) 代码,它没有给我任何授权标头,只有“缓存控制”和“内容类型”:

async function submitLogin(email, password) {
    let formData = new FormData();

    formData.append("user[email]", email)
    formData.append("user[password]", password)

    let result = await Axios.post(`${process.env.API_URL}/users/sign_in`, formData, {maxRedirects: 0})

    console.log(result)
}

the result:结果:

在此处输入图片说明

DISCLAMER: This is not a 100% answer to your question, but it will work for sure!免责声明:这不是您问题的 100% 答案,但它肯定会起作用!


In the case devise-jwt is not mandatory in your project, I would suggest you to follow what I did in my Rails 6 / React template :如果devise-jwt在您的项目中不是强制性的,我建议您遵循我在Rails 6 / React 模板中所做的:

  1. Configure you project routes in order to override the Devise's sessions routes like I did in my template project配置您的项目路由以覆盖设计的会话路由,就像我在模板项目中所做的那样
  2. Override the Devise's SessionController in order to make it responding with the JSON format and returning a JWT:覆盖 Devise 的SessionController以使其响应 JSON 格式并返回 JWT:
# frozen_string_literal: true

class SessionsController < Devise::SessionsController
  clear_respond_to
  respond_to :json

  def create
    super do |resource|
      if user_signed_in?
        resource.token = JwtWrapper.encode(user_id: current_user.id)
      end
    end
  end
end
  1. Add the JwtWrapper in app/helpers/jwt_wrapper.rb :添加JwtWrapperapp/helpers/jwt_wrapper.rb
# frozen_string_literal: true

module JWTWrapper
  extend self

  def encode(payload, expiration = nil)
    expiration ||= Rails.application.secrets.jwt_expiration_hours

    payload = payload.dup
    payload['exp'] = expiration.to_i.hours.from_now.to_i

    JWT.encode payload, Rails.application.secrets.jwt_secret
  end

  def decode(token)
    decoded_token = JWT.decode token, Rails.application.secrets.jwt_secret

    decoded_token.first
  rescue StandardError
    nil
  end
end

Now you'll get your valid JWT in the response body.现在,您将在响应正文中获得有效的 JWT。

Bonus奖金

I suggest you to have a look at the restful-json-api-client package which can handle JWT for you as it look for the token attribute in the responses and store and pass it to your requests.我建议您查看restful-json-api-client 包,它可以为您处理 JWT,因为它会在响应中查找token属性并将其存储并传递给您的请求。

It also handle JWT renewal automatically!它还自动处理 JWT 更新! So when you API replies with a 401 error, if you configure the renewal path, it will tries to renew the JWT.所以当你的 API 回复 401 错误时,如果你配置了更新路径,它会尝试更新 JWT。 If it succeeded, it will redo the query with the new JWT and it's transparent for your app, otherwise if it fails to renew it, it returns the failure to your app so that you can do something with it like redirecting your user to a login page.如果成功,它将使用新的 JWT 重做查询并且它对您的应用程序是透明的,否则如果它无法更新它,它会将失败返回给您的应用程序,以便您可以使用它执行某些操作,例如将您的用户重定向到登录页。

Hopefully this time I'm answering a little bit more to your question.希望这次我对你的问题回答得更多一点。 😇 😇

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM