Omniauth facebook会话控制器在Michael Hartl教程之后创建动作集成

mon*_*nie 5 ruby-on-rails omniauth railstutorial.org

我刚刚完成了Michael Hartl教程.我正在尝试实施omniauth-facebook注册和登录用户.我在创建要create在会话控制器中的操作中使用的主变量时遇到问题.我的假设是我应该if else发表声明,看看主人是通过Facebook登录还是通过默认表格?或者我应该使用and or声明:

(master = Master.find_by(email: params[:session][:email].downcase) || Master.from_omniauth(env["omniauth.auth"])) ?
Run Code Online (Sandbox Code Playgroud)

这是omniauth-facebook sessons控制器创建动作代码:

def create
    user = User.from_omniauth(env["omniauth.auth"])
    session[:user_id] = user.id
    redirect_to root_url
  end
Run Code Online (Sandbox Code Playgroud)

这是我当前的会话控制器创建动作代码:

class SessionsController < ApplicationController

    def new
    end

    def create
        master = Master.find_by(email: params[:session][:email].downcase)
        if master && master.authenticate(params[:session][:password])
            sign_in master
            redirect_back_or master
        else
            flash.now[:error] = 'Invalid email/password combination'
            render 'new'
        end
    end
    .
    .
    .


end
Run Code Online (Sandbox Code Playgroud)

Tim*_*dov 5

虽然我可能迟到一年才能回答这个问题,但我仍然认为像一年前那样出现类似问题的新观众可能会受益于以下答案

据我了解,实际问题是:

如何将Facebook身份验证从Scratch构建身份验证系统集成?

既然你说过你使用过迈克尔·哈特尔的教程,我就继续调整了迈克尔自己编写的认证系统的答案.现在让我们一步一步地遍历每一段代码.


1

首先,我们需要为现有的Users表创建两个额外的列,用于提供者uid,如下所示......

rails g migration add_facebook_auth_to_users provider uid

...并在Gemfile中添加omniauth-facebook gem ...

的Gemfile

gem 'omniauth-facebook', '2.0.1'

不要忘记之后运行bundle install和迁移数据库.


2

接下来我们需要继续编辑我们的Sessions控制器......

sessions_controller.rb

def create
  user = User.find_by(email: params[:session][:email].downcase)
  if user && user.authenticate(params[:session][:password])
    if user.activated?
      log_in user
      params[:session][:remember_me] == '1' ? remember(user) : forget(user)
      redirect_back_or user
    else
      message  = "Account not activated. "
      message += "Check your email for the activation link."
      flash[:warning] = message
      redirect_to root_url
    end
  else
    flash.now[:danger] = 'Invalid email/password combination'
    render 'new'
  end
end

def create_facebook
  user = User.from_omniauth(env["omniauth.auth"])
  log_in user
  redirect_back_or user 
end
Run Code Online (Sandbox Code Playgroud)

上面的会话控制器包含两个创建操作.第一个是直接从书中获取的未触及的方法,第二个是我专门用于Facebook身份验证的一段代码.

线user = User.from_omniauth(env["omniauth.auth"])有两个目的.创建用户如果他/她的唯一facebook uid不在数据库ELSE中,如果uid存在,则在应用程序中记录此人.稍后会详细介绍.


3

接下来让我们创建一个有效的.from_omniauth方法,您可以在问题中简要地显示代码内部...

user.rb

def self.from_omniauth(auth)
  where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap do |user|
    user.provider = auth.provider
    user.uid = auth.uid
    user.name = auth.info.name unless user.name != nil
    user.email =  SecureRandom.hex + '@example.com' unless user.email != nil
    user.activated = true
    user.password = SecureRandom.urlsafe_base64 unless user.password != nil
    user.save!
  end
end
Run Code Online (Sandbox Code Playgroud)

在这里,我们试图找到匹配给定用户provider,并uid从哈希值,然后我们呼吁first_or_initialize对这样的结果.此方法将返回第一个匹配记录或使用传入的参数初始化新记录.然后,我们调用tap此方法将该User实例传递给块.在块内部,我们根据OmniAuth哈希值设置用户的各种属性.

您可能会对为什么unless在一些属性初始化之后放置语句感兴趣.请考虑用户想要更新配置文件的情况,例如更改名称或smth,然后注销.当该用户最终决定重新登录时,该.from_omniauth方法将覆盖用户有问题的更新到原始的facebook值,除非我们阻止它这样做.

另请注意SecureRandom库的使用.在Michael Hartl在他的书中使用的传统身份验证中,他介绍了对电子邮件和密码提交的验证.电子邮件既不是空白也不是空白.同样,密码长度必须大于6个字符.由于电子邮件必须存在且独特,我决定使用电子邮件创建虚拟电子邮件SecureRandom.hex + @example.com.这将创建一个随机的十六进制字符串,52750b30ffbc7de3b362并将其追加@example.com,从而生成唯一的虚拟电子邮件.密码相同,但我更喜欢使用生成随机base64字符串SecureRandom.urlsafe_base64.最重要的是要记住Facebook用户不需要知道这些信息才能登录,因为这是使用Facebook身份验证的重点.这使他们可以在以后根据实际数据添加此信息.


4

现在是在主应用程序页面上添加按钮的好时机,供用户让他们实际登录到应用程序...

_header.html.erb

<% if logged_in? %>
  .
  .
  .
<% else %>
  .
  .
  <li><%= link_to "Sign in with Facebook", "/auth/facebook", id: "sign_in" %></li>
<% end %>
Run Code Online (Sandbox Code Playgroud)

那么,现在我们可以向facebook发送请求了.一个问题仍然是我们无法实际处理回调.为此,我们需要做以下事情......

  • 添加get 'auth/:provider/callback' => 'sessions#create_facebook'routes.rb文件

  • 使用Facebook提供的方便的Javascript SDK.让我们创建一个使用此SDK的自定义javascript文件...

应用程序/资产/ JavaScript的/ facebook.js.erb

jQuery(function() {
  $('body').prepend('<div id="fb-root"></div>');
  return $.ajax({
    url: window.location.protocol + "//connect.facebook.net/en_US/sdk.js",
    dataType: 'script',
    cache: true
  });
});

window.fbAsyncInit = function() {
  FB.init({
    appId: 'your_facebook_app_id_goes_here',
    version: 'v2.3',
    cookie: true
  });
  $('#sign_in').click(function(e) {
    e.preventDefault();
    return FB.login(function(response) {
      if (response.authResponse) {
        return window.location = '/auth/facebook/callback';
      }
    });
  });
  return $('#sign_out').click(function(e) {
    FB.getLoginStatus(function(response) {
      if (response.authResponse) {
        return FB.logout();
      }
    });
    return true;
  });
};
Run Code Online (Sandbox Code Playgroud)

6

就是这样,除了一个小小的警告......

问题

如果用户决定去编辑个人资料,他/她会看到我们的虚拟电子邮件显示在中间.这发生了,因为Rails足够聪明,可以自动填充用户的信息.在这种情况下,坦率地说,这非常令人尴尬.但是,好的方面是它很容易解决.只需在表单中将值设置为nil,就像这样......

<%= f.email_field :email, value: nil, class: 'form-control' %>


希望这有助于那些想从头开始构建身份验证系统的人:)