devise_token_auth omniauth JSON响应?

时间:2017-06-20 15:27:15

标签: ruby-on-rails json devise

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

  1. 管理区域
  2. 仅限API的客户区
  3. 我在两个部分使用Devise,为API前端使用https://github.com/lynndylanhurley/devise_token_auth gem。

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

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

    这是我的代码:

    配置/ 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
    

    应用/模型/ 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
    

    应用/控制器/用户/ 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
    

    配置/初始化/ 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
    

    的Gemfile

    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"}
    

    我猜这个问题是关于所谓的&#34;回调&#34;网址。我不明白它的位置。从日志中可以明显看出,在身份验证过程结束时,将调用GET "/omniauth/vkontakte/callback..."查询。并且可能总是被称为 - 无论我是从admin还是api客户区发起誓序序。

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

    是否有办法根据某些前提条件动态更改回调路径? 回调查询是否有所不同,具体取决于启动誓言程序的位置?

    EDIT1:

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

2 个答案:

答案 0 :(得分:0)

您可以根据请求从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)(或者您的路径帮助程序)

答案 1 :(得分:0)

我最终实现了自己的oauth回调程序 - 而不是使用devise_token_auth gem中的一个。

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

以下是我的代码更改:

<强>配置/ 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

应用/控制器/用户/ 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个auth标头:

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。