我的Rails应用程序使用Devise进行身份验证.它有一个姐妹iOS应用程序,用户可以使用他们用于Web应用程序的相同凭据登录iOS应用程序.所以我需要某种API进行身份验证.
这里有很多类似的问题指向本教程,但它似乎token_authenticatable已经过时了,因为该模块已从Devise中删除,并且某些行会抛出错误.(我正在使用Devise 3.2.2.)我试图根据那个教程(和这个教程)推出自己的教程(但是这个),但我对它没有100%的信心 - 我觉得我可能会有一些东西被误解或错过了.
首先,按照这个要点的建议,我authentication_token在我的users表中添加了一个text属性,以及以下内容user.rb:
before_save :ensure_authentication_token
def ensure_authentication_token
if authentication_token.blank?
self.authentication_token = generate_authentication_token
end
end
private
def generate_authentication_token
loop do
token = Devise.friendly_token
break token unless User.find_by(authentication_token: token)
end
end
Run Code Online (Sandbox Code Playgroud)
然后我有以下控制器:
api_controller.rb
class ApiController < ApplicationController
respond_to :json
skip_before_filter :authenticate_user!
protected
def user_params
params[:user].permit(:email, :password, :password_confirmation)
end
end
Run Code Online (Sandbox Code Playgroud)
(注意我application_controller有这条线before_filter :authenticate_user!.)
API/sessions_controller.rb
class Api::SessionsController < Devise::RegistrationsController
prepend_before_filter :require_no_authentication, :only …Run Code Online (Sandbox Code Playgroud) Django附带了CSRF保护中间件,它可以生成一个独特的每会话令牌,用于表单.它会扫描所有传入的POST请求以获取正确的令牌,并在令牌丢失或无效时拒绝该请求.
我想将AJAX用于一些POST请求,但是所述请求没有CSRF令牌可供选择.页面没有<form>可以挂钩的元素,我宁愿不把标记作为隐藏值插入标记.我认为这样做的一个好方法是公开一个/get-csrf-token/想要返回用户令牌的vew ,依靠浏览器的跨站点脚本规则来防止恶意站点请求它.
这是一个好主意吗?是否有更好的方法来防止CSRF攻击,同时仍允许AJAX请求?
你好,这是我在这里的第一篇文章!
我已经尝试调试这个问题几天了,但无法弄清楚。当我向 Rails api 发出发布请求时,我收到了以前从未见过的错误:
Started POST "/owners" for ::1 at 2021-01-12 11:24:15 -0500
(1.0ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
Processing by OwnersController#create as */*
Parameters: {"email"=>"adam", "password"=>"[FILTERED]", "owner"=>{"email"=>"adam"}}
HTTP Origin header (http://localhost:3000) didn't match request.base_url (http://localhost:3001)
Completed 422 Unprocessable Entity in 0ms (ActiveRecord: 1.8ms | Allocations: 476)
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
Run Code Online (Sandbox Code Playgroud)
就像我说的,我以前从未见过这种情况,我不知道我是如何造成它的。我没有使用代理服务器,我在这个项目中尝试的唯一可能搞砸的新事情是我安装了 devise gem,但决定不使用它并删除它。
我尝试过的事情:
确保我没有待处理的迁移:
检查我的路线:
Rails.application.routes.draw do
resources :owners
resources :dogs
post 'login', to: 'sessions#create'
end
Run Code Online (Sandbox Code Playgroud)
然后我认为这可能是一个cors问题:
require_relative 'boot'
require 'rails/all'
# Require the gems listed …Run Code Online (Sandbox Code Playgroud) 好。我正式对这个问题失去了理智。
我们使用默认的Rails应用程序(5,但我也尝试使用4默认应用程序)。
我正在尝试使用一个简单的javascript代码将ajax POST请求发送到一个控制器动作。
在我的ApplicationController代码中:
class ApplicationController < ActionController::Base
after_action :set_csrf_cookie
protected
def set_csrf_cookie
cookies["X-CSRF-Token"] = form_authenticity_token
end
end
Run Code Online (Sandbox Code Playgroud)
设置"X-CSRF-Token"值为的Cookie form_authenticity_token。
之后,我可以使用以下代码在SPA(单页应用程序)中读取此cookie:
<script>
function readCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(";");
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === " ") c = c.substring(1, c.length);
if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
// …Run Code Online (Sandbox Code Playgroud) 我需要使用带有Rails CSRF保护机制的单页应用程序(React,Ember,Angular,我不在乎)。
我想知道是否需要ApplicationController像这样创建令牌传送时间:
class ApplicationController < ActionController::Base
after_action :set_csrf_cookie
def set_csrf_cookie
cookies["X-CSRF-Token"] = form_authenticity_token
end
end
Run Code Online (Sandbox Code Playgroud)
或者我只能创建一次令牌。
每个会话还是每个(非GET)请求?
我认为令牌在会话有效之前仍然有效,对吗?
澄清:
每次浏览页面时,我看到Rails的默认应用程序(服务器呈现的页面)都会更新csrf令牌。因此,每次改变。
因此,在我的情况下,如果我为每个after_action会话创建一个新令牌,则以前的CSRF-Token对该会话仍然有用。那么,如何使先前的令牌无效?我必须?
因为只有当我使之无效时,对吗?
我在heroku创建了一个测试应用程序(使用scaffold),我在这个heroku应用程序中构建了一个iOS客户端(使用AFNetworking 2).我试图使用iOS应用程序从heroku中删除记录,但它无法正常工作.我从服务器收到422状态错误.
查看heroku日志,我发现服务器声称拥有CSRF令牌.所以我尝试在我的iOS客户端上使用此代码执行此操作:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.responseSerializer = [AFHTTPResponseSerializer new];
manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"application/json", nil];
[manager DELETE:contact.url parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"Response: %@", [operation description]) ;
if (block) {
block(error);
}
NSLog(@"Error: %@", error);
}];
Run Code Online (Sandbox Code Playgroud)
它没用.
如何在AFHTTPRequestOperationManager上将CSRF令牌添加到http标头中?