【问题标题】:devise_token_auth omniauth JSON response?devise_token_auth omniauth JSON 响应?
【发布时间】:2017-11-23 05:48:02
【问题描述】:

我有一个 Rails 5 站点,它由两部分组成:

  1. 管理区
  2. 仅限 API 的客户区

我将 Devise 用于这两个部分,https://github.com/lynndylanhurley/devise_token_auth gem 用于 API 前端。

问题在于使用omniauth 身份验证。当我通过omniauth 验证进入管理区域时——一切正常——我得到了一些成功的HTML 响应。

但问题是我在 API 区域获得了相同的 HTML 响应 - 但我需要一些 JSON 响应 - 而不是 HTML 响应。

这是我的代码:

config/routes.rb

Rails.application.routes.draw do

    devise_for :users, controllers: { sessions: 'users/sessions', :omniauth_callbacks => 'users/omniauth_callbacks' }

    namespace :api do   

        mount_devise_token_auth_for 'User', at: 'auth', controllers: { sessions: 'api/users/sessions', :omniauth_callbacks => 'api/users/omniauth_callbacks' }    

    end
end

app/models/user.rb

class User < ApplicationRecord

  # Include default devise modules.
  devise :database_authenticatable, :registerable,
          :recoverable, :rememberable, :trackable, :validatable,
          :omniauthable,
          :omniauth_providers => [:facebook, :vkontakte]

  include DeviseTokenAuth::Concerns::User

  devise :omniauthable

  def self.from_omniauth_vkontakte(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.email = auth.extra.raw_info.first_name.to_s + "." + auth.extra.raw_info.last_name.to_s + '@vk.com'      
      user.password = Devise.friendly_token[0,20]
    end
  end

end

app/controllers/users/omniauth_callbacks_controller.rb

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController

  def vkontakte
    @user = User.from_omniauth_vkontakte(request.env["omniauth.auth"])

    if @user.persisted?
      sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
      set_flash_message(:notice, :success, :kind => "Vkontakte") if is_navigational_format?
    else
      session["devise.vkontakte_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end    
  end

end

config/initializers/devise.rb

Devise.setup do |config|

  config.omniauth :facebook, ENV["FACEBOOK_APP_ID"], ENV["FACEBOOK_APP_SECRET"], provider_ignores_state: true

  config.omniauth :vkontakte, ENV["VKONTAKTE_APP_ID"], ENV["VKONTAKTE_APP_SECRET"]

end

宝石文件

gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-vkontakte'

Gemfile.lock

devise (4.3.0)
devise_token_auth (0.1.42)

这是我的日志:

Started GET "/api/auth/vkontakte" for 127.0.0.1 at 2017-06-20 17:34:23
+0300 
Started GET "/omniauth/vkontakte?namespace_name=api&resource_class=User" for
127.0.0.1 at 2017-06-20 17:34:23 +0300 
I, [2017-06-20T17:34:23.237270 #15747]  INFO -- omniauth: (vkontakte) Request phase initiated. 
Started GET "/omniauth/vkontakte/callback?code=0b8446c5fe6873bb12&state=52254649eb899e3b743779a1a4afc0304f249a6dd90b4415" for 127.0.0.1 at 2017-06-20 17:34:23 +0300 
I, [2017-06-20T17:34:23.672200 #15747]  INFO -- omniauth: (vkontakte) Callback phase initiated. Processing by Users::OmniauthCallbacksController#vkontakte as */*   Parameters: {"code"=>"0b8446c5fe6873bb12", "state"=>"52254649eb899e3b743779a1a4afc0304f249a6dd90b4415"}

我猜问题出在所谓的“回调”网址上。我不明白它在哪里设置。从日志中可以明显看出,在身份验证过程结束时调用了GET "/omniauth/vkontakte/callback..." 查询。并且它可能总是被调用 - 无论我是从管理员还是 api 客户端区域启动誓言序列。

我使用 Chrome Postman 进行 API 查询 http://localhost:3000/api/auth/vkontakte - 我得到了 HTML - 响应(“成功登录等”) - 但我肯定需要一些 JSON-响应。

有没有办法根据某些前提条件动态更改回调路径? 回调查询是否因宣誓程序的启动位置而有所不同?

EDIT1:

不幸的是,这不是一个单一的问题。看起来 oauth 根本没有在 https://github.com/lynndylanhurley/devise_token_auth gem 中实现。所以,即使我成功地将 oauth 登录过程切换到 JSON 方式 - 我如何登录用户 devise_token_auth 方式 - 生成 3 个令牌等......? app/controllers/users/omniauth_callbacks_controller.rb 需要完全重新实现。

【问题讨论】:

    标签: ruby-on-rails json devise


    【解决方案1】:

    我最终实现了自己的 oauth 回调过程 - 而不是使用来自 devise_token_auth gem 的回调过程。

    devise_token_auth gem 确实包含 oauth 身份验证 - 但它似乎无法正常工作。

    这是我的代码更改:

    config/routes.rb

    Rails.application.routes.draw do
    
        devise_for :users, controllers: { sessions: 'users/sessions', :omniauth_callbacks => 'users/omniauth_callbacks' }
    
        namespace :api do   
    
            mount_devise_token_auth_for 'User', at: 'auth', controllers: { sessions: 'api/users/sessions'}   
    
        end
    end
    

    app/controllers/users/omniauth_callbacks_controller.rb

    class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
      include DeviseTokenAuth::Concerns::SetUserByToken
    
      def vkontakte
        @user = User.from_omniauth_vkontakte(request.env["omniauth.auth"])
    
        namespace_name = request.env["omniauth.params"]["namespace_name"]
    
        if @user.persisted?
    
          if namespace_name && namespace_name == "api"
    
            @client_id = SecureRandom.urlsafe_base64(nil, false)
            @token     = SecureRandom.urlsafe_base64(nil, false)
    
            @user.tokens[@client_id] = {
              token: BCrypt::Password.create(@token),
              expiry: (Time.now + DeviseTokenAuth.token_lifespan).to_i
            }
            @user.save
    
            @resource = @user # trade-off for "update_auth_header" defined in "DeviseTokenAuth::Concerns::SetUserByToken"
    
            sign_in(:user, @user, store: false, bypass: false)        
    
            render json: @user
    
          else
    
            sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
            set_flash_message(:notice, :success, :kind => "Vkontakte") if is_navigational_format?
    
          end
    
        else
          session["devise.vkontakte_data"] = request.env["omniauth.auth"]
          redirect_to new_user_registration_url
        end    
      end
    
    end
    

    include DeviseTokenAuth::Concerns::SetUserByToken 的包含提供了 5 个身份验证标头作为响应:

    access-token →BeX35KJfYVheKifFdwMPag
    client →96a_7jXewCThas3mpe-NhA
    expiry →1499340863
    token-type →Bearer
    uid →376449571
    

    但响应仍然缺少这些标头(在普通登录时可用):

    Access-Control-Allow-Credentials →true
    Access-Control-Allow-Methods →GET, POST, PUT, PATCH, DELETE, OPTIONS
    Access-Control-Allow-Origin →chrome-extension://aicmkgpgakddgnaphhhpliifpcfhicfo
    Access-Control-Max-Age →1728000
    

    我不知道它们是否重要,如果是 - 如何提供它们。

    PS 同样的方法也适用于 Facebook。

    【讨论】:

      【解决方案2】:

      例如,当您从 API 请求连接时,您可以根据提供的一些额外参数从您的 OmniauthCallbacksController 呈现 json。 这些额外的参数将在此哈希 request.env["omniauth.params"] 中可用。

      class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
      
        def vkontakte
          @user = User.from_omniauth_vkontakte(request.env["omniauth.auth"])
      
          if @user.persisted?
            sign_in @user, :event => :authentication #this will throw if @user is not activated
            set_flash_message(:notice, :success, :kind => "Vkontakte") if is_navigational_format?
      
            if request.env["omniauth.params"]["apiRequest"]
              render status: 200, json: { message: "Login success" }
            else
              redirect_to after_sign_in_path_for(@user)
            end
          else
            session["devise.vkontakte_data"] = request.env["omniauth.auth"]
            redirect_to new_user_registration_url
          end
        end
      
      end
      

      您可以通过使用附加参数调用 auth 助手来获得这些额外参数,它们将被传递给您的 OmniauthController :user_vkontakte_omniauth_authorize_path(api_request: true)(或任何您的路由助手)

      【讨论】:

      • 我尝试GET http://localhost:3000/api/auth/vkontakte?api=true,但没有成功。远程服务器不会使用这个新参数调用我的回调。
      • 我犯了一个小错误,附加参数会在这里request.env["omniauth.params"]["api_request"],我已经更新了我的答案
      • 是的,这个确实有效。谢谢!而且我还找到了类似的解决方案:stackoverflow.com/questions/6396863/…。我的意思是GET http://localhost:3000/api/auth/vkontakte?api=true 导致request.env["omniauth.params"]["api"] 成为true
      • 我找到了一个更好的选择:我打电话给GET http://localhost:3000/api/auth/vkontakte,回调检查:request.env["omniauth.params"]["namespace_name"] == "api"。当我 oauth 进入管理区域时,这个值为nil。这种方法的好处是不需要初始查询的参数。
      • namespace_name 是具有omniauth 的默认参数?
      猜你喜欢
      • 1970-01-01
      • 2018-08-31
      • 2014-07-28
      • 1970-01-01
      • 2019-04-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-23
      • 1970-01-01
      相关资源
      最近更新 更多