【发布时间】:2011-04-12 03:24:07
【问题描述】:
使用 Rails 3.0.6、Omniauth 0.2.0 和 Devise 1.2.1,我遇到以下情况:
我想为用户提供通过 Facebook 进行身份验证的选项。我有一个使用 Devise 设置的用户系统,我可以使用 Facebook 成功进行身份验证。我花了几个小时尝试编写我想要针对一种特定情况的行为:
- 用户未登录
- 用户拥有站点帐户
- 用户通过 Facebook 进行身份验证
此时我为用户提供 2 个选择
- 创建一个帐户(可以是没有提供信息的虚拟帐户)
- 将此 Facebook 身份验证与现有帐户相关联
我在使用后一个选项时遇到了问题。用户已经通过身份验证,但我仍然需要他使用他的站点帐户登录。我的AuthenticationsController 中有一个操作,它将将此身份验证与登录用户相关联。不过,Devise 似乎没有为我提供一种在保持相同操作的同时登录用户的方法。这是我第一次尝试这样做
class AuthenticationsController < ApplicationController
before_filter :authenticate_user!, :only => :auth_link_existing_user
...
def auth_link_existing_user
...
end
但是,使用这种方法,如果用户登录,他们只会被重定向到我网站的根页面。我知道我可以更改 Devise 的登录重定向,但这将适用于所有登录。我只希望这种情况有一个单独的重定向。
在阅读了this 邮件列表问题后,我尝试用我自己的自定义行为扩展SessionsController:
def create
resource = warden.authenticate!(:scope => resource_name, :recall => "#{controller_path}#new")
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(resource_name, resource)
if params[:redirect] #new
redirect_to params[:redirect].to_sym #new
else
respond_with resource, :location => redirect_location(resource_name, resource)
end
end
这也不起作用。我已经定义了我的 auth_link_existing_user 路由以使用 POST 动词(这似乎是准确的),并且重定向只能是 GET。
所以现在我想到了一个解决方案:从 Devise 的 authenticate_user! 帮助器复制代码并将其粘贴到一个新函数中,该函数可以在控制器操作中调用而无需重定向。这对我来说似乎不太理想,因为它是代码的重复并增加了耦合——改变这种行为的设计或守望者更新也会破坏我的代码。
有没有其他人尝试过类似的方法并提出更优雅的解决方案?您有没有更简单的方法让我向我的用户提供这种或类似的行为?
更新:对于任何想在最后使用我的肮脏解决方案的人,这就是我所做的:
def auth_link_existing_user
# FROM Devise/sessions/create
resource = warden.authenticate!(:scope => :user, :recall => "registrations#auth_new")
set_flash_message(:notice, :signed_in) if is_navigational_format?
sign_in(:user, resource)
# method defined in Ryan Bates' Railscast for Omniauth w/Devise
current_user.apply_omniauth(session[:omniauth])
current_user.save
end
请注意,此操作必须放置在您的会话控制器中。如果没有,Warden 会给您一个“无效的电子邮件/密码”错误。寻找源代码的调试过程非常漫长。
有了这个,我在用户通过身份验证后使用登录表单提交到此操作。
【问题讨论】:
标签: ruby-on-rails-3 devise omniauth