如何让Rails API在另一个域上运行的客户端上的cookie中设置JWT?

Dia*_*ism 6 cookies ajax ruby-on-rails jwt reactjs

很久的潜伏者,第一次在这里发布海报.

有关JWT的许多良好指南和资源以及如何以及在何处存储它们.但是,当涉及到在节点服务器上运行的ReactJS/Flux应用程序和完全独立的Rails API之间安全地存储和发送JWT时,我陷入了僵局.

似乎大多数指南告诉您只需将JWT存储在本地存储中,然后为每个AJAX请求将其解析出来并将其传递到标题中.https://stormpath.com/blog/where-to-store-your-jwts-cookies-vs-html5-web-storage/警告不要这样做,因为本地存储不安全,恶意的人可以访问该令牌.它建议将其存储在cookie中,只是让Web浏览器将其与每个请求一起传递.

这听起来不错,因为根据我的理解,无论如何都可以方便地将cookie与每个请求一起发送.这意味着我可以从我的ReactJS应用程序向我的Rails API发出AJAX请求,并让API将其拔出,检查它,并做到这一点.*

我遇到的问题是我的Node应用程序没有从它从Rails API返回的响应中设置cookie,即使Rails API(在localhost:3000上运行)返回Set-Cookie标头并将其发送回ReactJS/Node应用程序(在localhost:8080上运行).

这是我的Rails API方面的登录控制器操作:

class V1::SessionsController < ApplicationController
  def create
    user = User.where(email: params[:user][:email]).first!
    if user && user.authenticate(params[:user][:password])
      token = issue_new_token_for(user)

      # I've tried this too.
      # cookies[:access_token] = {
      #     :value => token,
      #     :expires => 3.days.from_now,
      #     :domain => 'https://localhost:8080'
      # }

      response.headers['Set-Cookie'] = "access_token=#{token}"

      render json: { user: { id: user.id, email: user.email }, token: token }, status: 200
    else
      render json: { errors: 'username or password did not match' }, status: 422
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

它的要点是它需要一个电子邮件和密码,查看用户,并在信息检出时生成JWT.

这是从我的Node应用程序调用它的AJAX请求:

$.ajax({
    url: 'http://localhost:3000/v1/login',
    method: 'post',
    dataType: 'json',
    data: {
        user: {
            email: data.email,
            password: data.password
        },
        callback: '' //required to get around ajax CORS
    },
    success: function(response){
        console.log(response);
    },
    error: function(response) {
        console.log(response);
    }
})
Run Code Online (Sandbox Code Playgroud)

检查Rails API的响应显示它有一个Set-Cookie标头,其值为access_token = jwt.token.here

屏幕截图: Chrome Dev Tools Inspector屏幕截图

但是,localhost:8080没有显示任何cookie设置,并且我的Node/React应用程序的后续AJAX调用没有与它们一起发送任何cookie.

我的问题是,我误解了哪些内容.在这种情况下,如何在cookie中存储JWT需要做些什么?

一个后续问题:假设将JWT存储在cookie中不是一种选择,将JWT存储在本地存储中会有什么潜在的安全风险(假设我没有在JWT中放置任何敏感信息,它们都会在一些任意的时间)?

*这可能是我的一个根本误解.如果我有这个错误,请直截了当.

可能感兴趣的附注:

  • My Rails API具有CORS设置,仅允许来自localhost:8080的流量进行开发.
  • 在生产中,Node/React应用程序可能会在主域(example.com)上运行,而Rails API将在子域(api.example.com)上运行,但我还没有那么远.
  • 在我的JWT中没有任何敏感,所以本地存储是一个选项,但我想知道为什么我的设置不适用于cookie.

更新 elithrar提交了一个有效的答案:

我需要用xhrFields和crossDomain修改我的AJAX请求,并告诉jQuery支持cors:

$.support.cors = true;
$.ajax({
    url: 'http://localhost:3000/v1/login',
    method: 'post',
    dataType: 'json',
    xhrFields: {
        withCredentials: true
    },
    crossDomain: true,
    data: {
        user: {
            email: data.email,
            password: data.password
        }
    },
    success: function(response){
        console.log(response);
    },
    error: function(response) {
        console.log(response);
    }
})
Run Code Online (Sandbox Code Playgroud)

我添加了凭据:true并公开:我的Rails API上的Rack Cors配置是真的(*仅适用于我的开发环境):

config.middleware.insert_before 0, 'Rack::Cors' do
allow do
  origins '*'
  resource '*', :headers => :any, :methods => [:get, :post, :put, :path, :options], credentials: true, expose: true
end
Run Code Online (Sandbox Code Playgroud)

结束