2

我有一个使用 Grape 和 Devise 构建的 rails 应用程序来进行身份验证。该应用程序的范围是向 JavaScript 前端提供 API(所以这里根本没有 ERB)。

添加类 api 的 Warden/Devise 相关帮助程序部分后 < Grape::API 看起来像这样

resource :ticket do
    desc "Returns all tickets for a the requesting user; for admins, returns all tickets."
    get :all do
        authenticated_user
            @all_tickets = Ticket.where(user_id: current_user.id)
        end
    end
end

它工作得很好,它调用“authenticated_user”,如果返回用户登录,它返回数据。如果不是,则返回 401 - Unauthorized(使用 ajax 调用请求 json 响应)。用户当然必须先到http://domain.com/users/sign_in登录。然后它将重定向到可以进行所有这些调用的应用程序页面。

现在,为了应用程序流程,我需要让登录表单基于 ajax。从用户在应用程序中的任何时间开始。

我已经按照教程Ajax Login with Devise和许多其他人进行了操作。但这对我来说更有意义。但是我得到了非常奇怪的结果。

考虑以下 JavaScript 代码:

$('#login').click(function (e) {
$.ajax({
    url: 'http://api.domain.com/users/sign_in?',
    type: 'post',
    data: {remote: true, commit: "Sign in", utf8: "✓", user: {remember_me: 0, password: "12345678", email: "admin@domain.com"}},
    format: "json",
    xhrFields: { withCredentials: true },
        success: function (data) {
            console.log(data);
        }
    });     
});

请注意,我使用 cors/rack 来执行跨域调用。有2种情况:

1 - 当我拨打这个电话时,我得到状态 200 OK。但是,cookie 集不足以执行需要身份验证的 api 调用。因此,api 调用返回 401 - 未经授权。

2 - 如果我将“remember_me”设置为 true(或 0),然后单击登录按钮,它将第一次返回 200OK。它不会随请求发送 cookie(因为在我退出时还没有 cookie)。响应标头中带有 rails cookie,响应为 200 OK。

然而,在那次调用之后,我第二次点击登录按钮,它返回“302 临时移动”,然后另一个请求命中 domain.com/ - 之后我通过了身份验证。当我进行需要身份验证的 API 调用时,将返回数据。这次发送了 cookie(从第一次登录尝试中获得),并在响应标头中返回了另一个 cookie。这个和我发的不一样,我认为是因为 CSRF。每次发送 cookie 时,都会用新的令牌返回一个新的 cookie。

在执行 API 调用时,我必须使用 "xhrFields: { withCredentials: true}" 以便能够随请求发送 cookie,以便设计可以验证 API 调用者。因此,如果我使用默认的 Devise 表单登录,则数据会轻松返回。

另一种选择是沿着请求发送 CSRF 令牌(从 HTML 的元数据中获取),但正如我上面解释的那样,我正在构建一个客户端 JS 客户端,并且页面不会从 rails 本身呈现。

有没有办法使用 ajax 使用 Devise 登录,而不必拨打两次电话?

提前致谢!DD

4

0 回答 0