用Devise+Omniauth实现第三方登录

用Devise+OmniAuth实现第三方登录(Google,Facebook,Githu)

▶︎原理图


这逻辑图建议大家开始之前看一遍
做完以后再看一遍
相信再不会有什么问题

▶︎准备工作

①配置Gem

  1. 在Gemfile中加入以下gem

    gem 'omniauth'
    gem 'omniauth-google-oauth2'
    gem 'omniauth-facebook'
    gem 'omniauth-github'
    gem 'figaro'

  2. bundle install

  3. figaro install

②给User加Username

  1. 终端输入 rails generate migration add_username_to_users username:string:uniq
  2. 终端输入 rake db:migrate
  3. 在User.rb中
    ruby
    validates :username, presence: true, length: {maximum: 25}

  4. 在ApplicationController.rb中填入一下内容

    class ApplicationController < ActionController::Base
    before_action :configure_permitted_parameters, if: :devise_controller?
    
    protected
    
    def configure_permitted_parameters
        added_attrs = [:username, :email, :password, :password_confirmation, :remember_me]
        devise_parameter_sanitizer.permit :sign_up, keys: added_attrs
        devise_parameter_sanitizer.permit :account_update, keys: added_attrs<<:current_password
    end
    end
    

    这里注意,把protected以及它后面的内容都写在最后面

③给User加Image

  1. 终端输入 rails g migration add_image_to_users image:string
  2. 终端输入 rake db:migrate

④创建一个叫Identify的model

  1. 终端输入rails g model identify user_id:integer provider:string uid:string
  2. 在User.rb中,填入
    ruby
    has_many :identifies

  3. 在Identify.rb中,填入
    ruby
    belongs_to :user

  4. 终端输入 rake db:migrate
    现在user与identify形成了一对多的关系(举例:一个user对应一个google的identify,一个facebook的identify,一个gihub的identify))

▶︎实现Google登录

①配置路由生成authorize与callback两个网址

  1. 在User.rb中的devise 一行里添加一个:omniauthable ruby devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable

注意:validatable后面的逗号不要掉了

  1. 在devise.rb中填入
   require 'omniauth-google-oauth2'
   config.omniauth :google_oauth2, ENV["GOOGLE_CLIENT_ID"], ENV["GOOGLE_CLIENT_SECRET"], {access_type: "offline", approval_prompt: ""}

3 . 在终端中输入rake routes你就可以看到,它们做产生的两个访问网址


这个user_google_oauth2_omniauth_authorize的处理已经由devise+omniauth帮我们搞定了,
剩下这个user_google_oauth2_omniauth_callback需要我们自己建立一个controller来处理
所以下面就是来建立这个callback回调controller

②建立callback回调controller

  1. 在routes.rb中的devise_for :users后面填上如下内容
    devise_for :users, :controllers => {:omniauth_callbacks => "omniauth_callbacks"}
    
    目的是让routes知道,未来当devise接受到认证回调消息的时候,由一个叫omniauth_callbacks的controller来处理(下一步我们就会创建它)
  2. 在终端输入rails g controller omniauth_callbacks
  3. 去到这个新建的omniauth_callbacks_controller.rb中,填入以下内容

    def google_oauth2
    @user = User.from_google(request.env["omniauth.auth"], current_user)
    
    if @user.persisted?
        flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Google"
        sign_in_and_redirect @user, :event => :authentication
    else
        session["devise.user_data"] = request.env["omniauth.auth"]
        redirect_to new_user_registration_path
    end
    end
    

    注意User又一个from_google的方法,我们还没有定义,下面就去定义

③定义User的from_google方法

在User.rb中填入以下内容

  def self.from_google(access_token, signed_in_resource=nil)
    data = access_token.info
    identify = Identify.find_by(:provider => access_token.provider, :uid => access_token.uid)

    if identify
        return identify.user
    else
        user = User.find_by(:email => access_token.email)
        if !user
            user = User.create(
                username: data["name"],
                email: data["email"],
                image: data["image"],
                password: Devise.friendly_token[0,20]
            )
        end
            identify = Identify.create(
                provider: access_token.provider,
                uid: access_token.uid,
                user: user
            )
        return user
    end
  end

④在Google开发者平台上建立应用并拿到app_id与secret_key

  1. 登录Google开发者平台 Google Cloud Platform
  2. 创建一个应用
  3. 起个名字点击创建
  4. 确保在自己新建的项目中,并点击左侧Library,然后分别去往Contacts API与Google+ API中,点选enable
  5. 设置product名称
  6. 点击左侧Credentials然后点选中间Create credentials下拉菜单中的OAuth client ID
  7. 填表单相应需要的内容
    注意,第四步里,建议填入两个 第一个是本地开发用的http://localhost:3000/users/auth/google_oauth2/callback 第二个是你自己heroku项目的回调网址https://meizhebao.herokuapp.com/users/auth/google_oauth2/callback
  8. 获得Client ID与Client Secret


    你可自己拷贝记录下来,也可以放在这里,我们马上就要使用

    ⑤用figaro来管理你的google client id 与 secret key

  9. 在config/application.yml中填入以下内容

    production:
    GOOGLE_CLIENT_ID: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    GOOGLE_CLIENT_SECRET: 'xxxxxxxxxxxxxxx'
    development:
    GOOGLE_CLIENT_ID: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    GOOGLE_CLIENT_SECRET: 'xxxxxxxxxxxxxxx'
    

    2 . 把你刚才拿到的client ID 与 client secret分别去替换application.yml中的内容

    现在controller,routes,model都配置完毕,可以去view中放一个用google登录注册的按钮了

⑥创建Google一键登录按钮

  1. 终端中输入rails g devise:views
  2. 在app/views/devise/registrations/new.html.erb中 Sign Up标题的下面填入一行代码
    <%= link_to "用Google登录", user_google_oauth2_omniauth_authorize_path, class: "btn btn-primary" %>
    
    ## 大功告成 现在就可以去试一试google登录了

▶︎实现用Facebook登录

①前面已实现的内容

Gemfile中引用gem 'omniauth-facebook'
已经给user添加了usernmae
已经创建identify
已经给user添加image
下面略微有一点不同,就照老步骤来

②配置路由生成authorize与callback两个网址

  1. 【之前已实现,可跳过】在User.rb中的devise 一行里添加一个:omniauthable
  2. 在devise.rb中填入
      require 'omniauth-facebook'
    config.omniauth :facebook, ENV["FACEBOOK_CLIENT_ID"], ENV["FACEBOOK_CLIENT_SECRET"]
    
    3 . 在终端中输入rake routes你就可以看到,新产生的两个facebook访问验证网址
    这个user_github_omniauth_authorize的处理已经由devise+omniauth帮我们搞定了, 剩下这个user_github_omniauth_callback需要我们自己建立一个controller来处理 所以下面就是来建立这个callback回调controller

③建立callback回调controller

  1. 【之前已实现,就可跳过】在routes.rb中的devise_for :users后面填上如下内容
    devise_for :users, :controllers => {:omniauth_callbacks => "omniauth_callbacks"}
    
    目的是让routes知道,未来当devise接受到认证回调消息的时候,由一个叫omniauth_callbacks的controller来处理(下一步我们就会创建它)
  2. 【之前已实现,可跳过】在终端输入rails g controller omniauth_callbacks
  3. 在这个新建的omniauth_callbacks_controller.rb中,填入以下内容

    def facebook
    @user = User.from_facebook(request.env["omniauth.auth"], current_user)
    
    if @user.persisted?
        flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Facebook"
        sign_in_and_redirect @user, :event => :authentication
    else
        session["devise.user_data"] = request.env["omniauth.auth"]
        redirect_to new_user_registration_path
    end
    end
    

    注意User有一个from_github的方法,我们还没有定义,下面就去定义

④定义User的from_facebook方法

在User.rb中填入以下内容

  def self.from_facebook(access_token, signed_in_resoruce=nil)
        data = access_token.info
        identify = Identify.find_by(provider: access_token.provider, uid: access_token.uid)
    
        if identify
            return identify.user
        else
            user = User.find_by(:email => data.email)
            if !user
                user = User.create(
                    username: access_token.extra.raw_info.name,
                    email: data.email,
                    image: data.image,
                    password: Devise.friendly_token[0,20]
                )
            end
            identify = Identify.create(
                provider: access_token.provider,
                uid: access_token.uid,
                user: user
            )
            return user
        end
  end

⑤在facebook开发者平台上建立应用并拿到app_id与secret_key

  1. 登录 facebook开发者平台
  2. 创建一个新应用
  3. 开启facebook登录的功能
  4. 输入项目和localhost地址
  5. 拿到client id与client secret
  6. 公开你的应用

⑥用figaro来管理你的facebook client id 与 secret key

  1. 在config/application.yml中填入以下内容
    production:
    GOOGLE_CLIENT_ID: 'oooooooooooooooooooooooooooooooooo'
    GOOGLE_CLIENT_SECRET: 'oooooooooooo'
    FACEBOOK_CLIENT_ID: 'xxxxxxxxxxx'
    FACEBOOK_CLIENT_SECRET: 'xxxxxxxxxxxxxxxxxxxxxxxx'
    development:
    GOOGLE_CLIENT_ID: 'oooooooooooooooooooooooooooooooooo'
    GOOGLE_CLIENT_SECRET: 'oooooooooooo'
    FACEBOOK_CLIENT_ID: 'xxxxxxxxxxx'
    FACEBOOK_CLIENT_SECRET: 'xxxxxxxxxxxxxxxxxxxxxxxx'
    
    2 . 把你刚才拿到的client ID 与 client secret分别去替换application.yml中的FACEBOOK_CLIENT_ID与FACEBOOK_CLIENT_SECRET的内容 > 现在controller,routes,model都配置完毕,可以去view中放一个用gihub登录注册的按钮了

⑦创建Facebook一键登录按钮

  1. 【以实现,可跳过】终端中输入rails g devise:views
  2. 在app/views/devise/registrations/new.html.erb中 Sign Up标题的下面填入一行代码
    <%= link_to "用Facebook登录", user_facebook_omniauth_authorize_path, class: "btn btn-info" %>
    
    ## 大功告成 现在就可以去试一试google登录了

▶︎实现用Github登录

①前面已实现的内容

Gemfile中引用gem 'omniauth-github'
已经给user添加了usernmae
已经创建identify
已经给user添加image
下面略微有一点不同,就照老步骤来

②配置路由生成authorize与callback两个网址

  1. 在User.rb中的devise 一行里添加一个:omniauthable 这一步前文已做,所以跳过
  2. 在devise.rb中填入
      require 'omniauth-github'
    config.omniauth :github, ENV["GITHUB_CLIENT_ID"], ENV["GITHUB_CLIENT_SECRET"], scope: "user:email"
    
    3 . 在终端中输入rake routes你就可以看到,新产生的两个github访问验证网址
    这个user_github_omniauth_authorize的处理已经由devise+omniauth帮我们搞定了, 剩下这个user_github_omniauth_callback需要我们自己建立一个controller来处理 所以下面就是来建立这个callback回调controller

③建立callback回调controller

  1. 【之前已实现,就可跳过】在routes.rb中的devise_for :users后面填上如下内容
    devise_for :users, :controllers => {:omniauth_callbacks => "omniauth_callbacks"}
    
    目的是让routes知道,未来当devise接受到认证回调消息的时候,由一个叫omniauth_callbacks的controller来处理(下一步我们就会创建它)
  2. 【已实现,可跳过】在终端输入rails g controller omniauth_callbacks
  3. 在这个新建的omniauth_callbacks_controller.rb中,填入以下内容

    def github
    @user = User.from_github(request.env["omniauth.auth"], current_user)
    
    if @user.persisted?
        flash[:notice] = I18n.t "devise.omniauth_callbacks.success", :kind => "Github"
        sign_in_and_redirect @user, :event => :authentication
    else
        session["devise.user_data"] = request.env["omniauth.auth"]
        redirect_to new_user_registration_url
    end
    end
    

    注意User有一个from_github的方法,我们还没有定义,下面就去定义

④定义User的from_github方法

在User.rb中填入以下内容

  def self.from_github(access_token, signed_in_resoruce=nil)
        data = access_token["info"]
        identify = Identify.find_by(provider: access_token["provider"], uid: access_token["uid"])
    
        if identify
            return identify.user
        else
            user = User.find_by(:email => data["email"])
    
            if !user
    
                if data["name"].nil?
                    name = data["nickname"]
                else
                    name = data["name"]
                end
    
                user = User.create(
                    username: name,
                    email: data["email"],
                    image: data["image"],
                    password: Devise.friendly_token[0,20]
                )
            end
    
            identify = Identify.create(
                provider: access_token["provider"],
                uid: access_token["uid"],
                user: user
            )
    
            return user
        end
  end

⑤在Github后台上建立应用并拿到app_id与secret_key

  1. 进入Github设置
  2. 创建一个新的应用
  3. 填入相应的名字和网址以及回调网址
    > 这里注意,将来你上传到heroku上以后,要把这两个地址换成你项目的地址和项目的回调地址
  4. 注册后就可以拿到Client ID与Client Secret了

⑥用figaro来管理你的github client id 与 secret key

  1. 在config/application.yml中填入以下内容
    production:
    GOOGLE_CLIENT_ID: 'oooooooooooooooooooooooooooooooooo'
    GOOGLE_CLIENT_SECRET: 'oooooooooooo'
    FACEBOOK_CLIENT_ID: 'oooooooooooo'
    FACEBOOK_CLIENT_SECRET: 'oooooooooooooooooooooooooooooo'
    GITHUB_CLIENT_ID: 'xxxxxxxxxxxxxxx'
    GITHUB_CLIENT_SECRET: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    development:
    GOOGLE_CLIENT_ID: 'oooooooooooooooooooooooooooooooooo'
    GOOGLE_CLIENT_SECRET: 'oooooooooooo'
    FACEBOOK_CLIENT_ID: 'oooooooooooo'
    FACEBOOK_CLIENT_SECRET: 'oooooooooooooooooooooooooooooo'
    GITHUB_CLIENT_ID: 'xxxxxxxxxxxxxxx'
    GITHUB_CLIENT_SECRET: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    
    2 . 把你刚才拿到的client ID 与 client secret分别去替换application.yml中的GITHUB_CLIENT_ID与GITHUB_CLIENT_SECRET的内容 > 现在controller,routes,model都配置完毕,可以去view中放一个用gihub登录注册的按钮了

⑦创建Gighub一键登录按钮

  1. 【以实现,可跳过】终端中输入rails g devise:views
  2. 在app/views/devise/registrations/new.html.erb中 Sign Up标题的下面填入一行代码
    <%= link_to "Sign up with Github", user_github_omniauth_authorize_path, class: "btn btn-danger" %>
    
    ## 大功告成 现在就可以去试一试Github登录了

最后的最后

记住把项目上传到heroku上之后
要通过输入figaro heroku:set -e production
把所有id和secret_key都上传到heroku上才能使用

核心代码解析

参考资料

devise wiki
Rails4 omniauth using devise with twitter facebook and linkedin
How To Setup Devise and OmniAuth for Your Rails Application
devise wiki



往期分享

吉翔

Github仓库备份
中文字体自定义
魔改大赛这样开始比较快
商品无限级分类

董明娟

Panel+Grid作出清爽购物车
bootstrap实现About翻转卡片