我在Rails中编写应用程序的后端。当我在后端工作时,我需要给前端开发人员一个REST API来开始构建前端。最终,前端和后端将一起驻留在一个应用程序中,但现在它们是分开的。
暂时我在我的应用中启用了跨源资源共享,方法是在ApplicationController
添加以下内容:
config.action_dispatch.default_headers.merge!({
'Access-Control-Allow-Origin' => '*',
'Access-Control-Request-Method' => '*'
});
目前,我还通过在application.rb
添加以下内容来关闭CSRF令牌:
skip_before_filter :verify_authenticity_token
我正在使用Devise来验证用户身份。为了使Devise能够处理JSON请求,我已经完成了以下操作:
在devise.rb
config.navigational_formats = ['*/*', :html, :json]
在routes.rb
devise_for :users, :controllers => {:omniauth_callbacks => "omniauth_callbacks", :sessions => 'sessions', :registrations => 'registrations' }
我的SessionsController
class SessionsController < Devise::SessionsController
#todo had to do following to support logging in through ajax. need to add logic to send back error response when login fails.
#todo see http://stackoverflow.com/questions/5973327/using-devise-1-3-to-authenticate-json-login-requests/8402035#8402035 and
#todo https://web.archive.org/web/20130928040249/http://jessehowarth.com/devise
#todo see http://stackoverflow.com/questions/11277300/devise-failure-authentication-via-json-sends-back-html-instead-of-json
def create
respond_to do |format|
format.html { super }
format.json {
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#failure")
sign_in(resource_name, resource)
return render :json => {:success => true, :user => resource}
}
end
end
def destroy
respond_to do |format|
format.html { super }
format.json {
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
render :json => {}
}
end
end
def failure
render :json => {:success => false, :errors => ["Login Failed"]}, :status => 422
end
end
我有一个扩展的Devise的RegistrationsController以及routes.rb中的指示,但我没有在这里发布它的内容,因为我不认为这与这个问题有关。
通过上述设置,我可以使用用户[email]和用户[密码]参数向'/ users / sign_in'发送ajax请求,并让用户登录。响应如下所示:
{
success: true
user: {
authentication_token: "SNa2kPqkm5ENsZMx7yEi"
created_at: "2014-12-16T02:40:39.179Z"
email: "xyz@xyz.com"
id: 99999
name: null
provider: null
uid: null
updated_at: "2014-12-17T02:29:31.537Z"
}
}
现在我如何使用sign_in响应中收到的authentication_token将请求发送到需要用户进行身份验证的其他控制器操作?我是否需要在请求标头中设置此标记?我无法找到有关如何使用此令牌的信息。请帮忙。
答案 0 :(得分:0)
似乎按照这里的要点所述,答案是你向后端发送suer的电子邮件和authentictication_token以及每个请求。您可以选择在请求标头中发送它或仅作为参数发送它。您只需修改检查电子邮件和令牌的方法,并相应地在ApplicationController中签名用户。这是我的ApplicationController(我现在在请求中发送电子邮件和令牌作为参数):
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
#todo remove this once ui is integrated. following turns off the csrf token:
skip_before_filter :verify_authenticity_token
#todo begin code to support authentication using token
# This is our new function that comes before Devise's one
before_filter :authenticate_user_from_token!
# This is Devise's authentication
before_filter :authenticate_user!
private
def authenticate_user_from_token!
user_email = params[:user_email].presence
user = user_email && User.find_by_email(user_email)
# Notice how we use Devise.secure_compare to compare the token
# in the database with the token given in the params, mitigating
# timing attacks.
if user && Devise.secure_compare(user.authentication_token, params[:user_token])
sign_in user, store: false
end
end
#todo end code to support authentication using token
end
我忘了在帖子中提到我已经添加了迁移以向用户模型添加authentication_token列。此外,我必须在User模型中添加以下内容(如gist中所述),以便每次创建/更新用户时都会生成身份验证令牌:
#todo begin code to support ajax authentication of users
#todo see https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
# You likely have this before callback set up for the token.
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.where(authentication_token: token).first
end
end
#todo end code to support ajax authentication of users