我来回答一下问题。本文解释了全部细节:https :
//blog.eq8.eu/article/rails-api-authentication-with-spa-csrf-tokens.html
鉴于 Rails 正在为 SPA 设置 cookie
CSRF 令牌在会话的生命周期内有效。因此,是的,在登录后的会话期间生成一个 CSRF 令牌是可以的。
class LoginController < ApplicationController
def create
if user_password_match
# ....
cookie[:my_csrf_token]= form_authenticity_token
end
end
end
或者您可以按照您提议的方式刷新 cookie
class ApplicationController < ActionController::Base
after_action :set_csrf_cookie
def set_csrf_cookie
cookies["my_csrf_token"] = form_authenticity_token
end
end
您的 SPA 只需要读取 cookie 并将其设置为标题。
两者同样有效
或者您可以只提供 CSRF 令牌作为登录响应,SPA 会将其存储在某处并在X-CSRF-Token
标头中使用它:
curl POST https://api.my-app.com/login.json -d "{"email":'equivalent@eq8.eu", "password":"Hello"}" -H 'ContentType: application/json'
# Cookie with session_id was set
# response:
{ "login": "ok", "csrf": 'yyyyyyyyy" }
# next request
curl POST https://api.my-app.com/transfer_my_money -d "{"to_user_id:":"1234"}" -H "ContentType: application/json" -H "X-CSRF-Token: yyyyyyyyy"
鉴于 Rails 接受仅标头身份验证
如果您不使用 cookie 发送 session_id,那么您的 API 仅使用Authentication
标头进行身份验证。那么你就不需要 CSRF 保护了。
没有会话 cookie 没有 CSRF 问题!
例子:
curl POST https://api.my-app.com/login.json -d "{"email":'equivalent@eq8.eu", "password":"Hello"}" -H 'ContentType: application/json'
# No cookie/session is set
# response:
{ "login": "ok", "jwt": "xxxxxxxxxxx.xxxxxxxx.xxxxx" }
# Next Request:
curl POST https://api.my-app.com/transfer_my_money -d "{"to_user_id:":"1234"}" -H "ContentType: application/json" -H "Authentication: Bearer xxxxxxxxxxx.xxxxxxxx.xxxxx"
再一次,这只是当您不使用 cookie 进行用户识别时!因此,在这种情况下,CSRF 不是问题,但您仍然可以防止跨站点脚本攻击,确保您的通信仅是 HTTPs,等等......