如何在Azure AD上使用SSO设置RoR应用程序

时间:2016-07-07 10:02:30

标签: ruby-on-rails devise single-sign-on azure-active-directory adal

我正在努力设置一个使用ActiveAdmin进行身份验证的Ruby on Rails Devise应用程序。我使用Azure AD strategy进行omniauth策略。

我在config/initializers/devise.rb中添加了omniauth策略:

config.omniauth :azure_activedirectory, 'app id', 'azure tenant id'

添加了Users::OmniauthCallbacksContoller

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def azure_activedirectory
    @user = AdminUser.from_omniauth(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 => 'azure_activedirectory') if is_navigational_format?
    else
      session['devise.azure_activedirectory_data'] = request.env['omniauth.auth']
      redirect_to new_admin_user_registration_url
    end
  end

  def failure
    redirect_to root_path
  end
end

并将回调路线添加到routes.rb

Rails.application.routes.draw do
  devise_config = ActiveAdmin::Devise.config
  devise_config[:controllers][:omniauth_callbacks] = 'users/omniauth_callbacks'
  devise_for :admin_users, devise_config

  devise_scope :admin_user do
    get 'sign_in', :to => 'devise/sign_in', as: :new_admin_user_session
    get 'sign_out', :to => 'devise/sign_out', :as => :destroy_admin_user_session
  end

  ActiveAdmin.routes(self)

  root to: redirect('/admin')
end

from_omniauth方法添加到models/admin_user

class AdminUser < ActiveRecord::Base
  devise :trackable, :omniauthable, omniauth_providers: [:azure_activedirectory]

  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.email = auth.info.email
      user.password = Devise.friendly_token[0,20]
    end
  end
end

但是我运行应用程序时得到的只是错误:The action 'sign_in' could not be found for Users::OmniauthCallbacksController

我现在已经结束了,我不知道我还需要做些什么才能让它发挥作用。 https://github.com/AzureAD/omniauth-azure-activedirectoryhttps://github.com/plataformatec/devise/wiki/OmniAuth:-Overview不再为我提供任何有关如何修复它的线索。

有人可以帮我解决我的错误吗?

2 个答案:

答案 0 :(得分:4)

我们已经开展了更多项目,并且能够解决Azure AD身份验证问题。然而,我们遇到了一些事情。

默认情况下,azure活动目录策略生成没有下划线的路由。因此,请确保用于身份验证的模型使用:

  

omniauth_providers:[:azureactivedirectory] ​​

该模型还扩展了字段&#34; provider&#34;和&#34; uid&#34;。

Devise将在页面上添加一个链接(c.q。按钮)进行登录。但我们的目标是仅支持omniauth身份验证,因此没有额外的登录页面。为实现这一目标,我们添加了一个重定向,以便将认证直接转发给azure提供商。

更改映射时也要小心(在config / initializers / device.rb中)。我们添加了一个解决方法,以防Devise无法找到:api作用域的身份验证失败处理程序。在我们的例子中,由于映射原因,我们最终处于循环中,因此在我们的应用程序中未正确设置身份验证。我们的应用程序将我们引导到Azure进行身份验证,而Azure重新定向了我们,因为我们已经过身份验证,然后是应用程序指示我们......等等。

以下是一些可能有用的代码段:

<强>配置/ routes.rb中

Rails.application.routes.draw do

  devise_config = ActiveAdmin::Devise.config
  # see https://github.com/activeadmin/activeadmin/wiki/Log-in-through-OAuth-providers  
  # for how to combine settings in devise config from ActiveAdmin and SamlSessions
  devise_config[:controllers][:omniauth_callbacks] = 'omniauth_callbacks'
  devise_config[:skip] = [:sessions]
  devise_for :admin_users, devise_config

  devise_scope :admin_user do
    get 'sign_in', :to => redirect('/admin/auth/azureactivedirectory'), :as => :new_admin_user_session
    get 'sign_out', :to => 'devise/sessions#destroy', :as => :destroy_admin_user_session
end

ActiveAdmin.routes(self)
...
...

应用/模型/ admin_user.rb

class AdminUser < ActiveRecord::Base

  devise :trackable, :omniauthable, omniauth_providers: [:azureactivedirectory]

  def self.from_omniauth(auth)
    where(provider: auth['provider'], uid: auth['uid']).first_or_create do |user|
      user.email = auth['info']['email']
    end
  end
end

app / controllers / omniauth_callbacks_controller.rb

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
  skip_before_filter :verify_authenticity_token

  def azureactivedirectory
    @user = AdminUser.from_omniauth(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 => 'azure_activedirectory') if is_navigational_format?
    else
      session['devise.azure_activedirectory_data'] = request.env['omniauth.auth']
      redirect_to new_admin_user_registration_url
    end
  end

  def failure
    redirect_to root_path
  end
end

答案 1 :(得分:0)

我认为你不需要这一行:

get 'sign_in', :to => 'devise/sign_in', as: :new_admin_user_session

Devise Docs上,如果您使用:

devise_for :admin_users

Devise将自动创建登录路线,因此您只需使用:

<%= link_to "Sign in with AzureAD", admin_user_omniauth_authorize_path(:azure_activedirectory) %>

我希望它可以帮助你:)

<强>更新

登录后,您可以指定希望用户重定向到的路径,如您所见[{3}}和here,为此您可以在应用程序中指定这些方法控制器:

def after_sign_in_path_for(resource)
  current_user_path
end

def after_sign_out_path_for(resource_or_scope)
  request.referrer
end

更新2

您正在从'/'重定向到'/ admin',因为您的config / routes.rb上的这一行

root to: redirect('/admin')

这是设置应用程序的根目录,默认为'/'为'/ admin'。如果删除此行,rails会将应用程序的根识别为“/”。