ios - 具有 Web + iOS 应用程序身份验证的 Rails Azure Active Directory SSO

标签 ios ruby-on-rails ruby swift azure

我需要让用户从 iOS 应用程序登录到他们的 Azure Active Directory 帐户,并在获取 token 后将信息传递到我的 Rails 服务器,然后该服务器将对用户进行身份验证并创建其本地 (Rails) 用户记录如果认证成功。或者,对于现有用户,它(理想情况下)会设置 Devise current_user 变量,以便后续对 Rails 应用程序上的资源的请求能够成功。

我让这个等式的两边独立工作——iOS/Swift 4应用程序使用Microsoft SDK来获取 token ——它工作正常。 Rails 端使用 Azure Active Directory Omniauth 提供程序进行设置,当您通过浏览器访问它时,它可以正常工作。到目前为止,一切都很好。 (注意:两者都使用 Azure AD v1.0 API:iOS 上的 ADAL 和 Rails 上的omniauth-azure-activedirectory)

当我过去使用 Omniauth 时(特别是使用 Facebook 提供商),我可以在应用程序端获取 token 并将其传递到 Rails 服务器,然后 Rails 服务器将使用 Facebook 图表来确保通过简单的 GET 请求, token 是合法的。然而,使用 Microsoft Omniauth 提供程序时,似乎没有等效的解决方案。我发现 token 和声明在两者之间匹配,但我不知道向 Rails 指示用户是合法的,并且如果身份验证详细信息匹配,则应在 Devise 中实例化为 current_user 的最佳方法。换句话说,我应该将哪些字段发送到 Rails 端,然后将其传递到 Azure AD 以验证用户的真实性?

我应该尝试使用 Omniauth 提供程序并返回基于 Web 的版本提供的内容(例如omniauth.auth 哈希),还是应该编写自己的 Controller /操作来从应用程序接收身份验证详细信息并实例化用户在从 Rails 再次验证用户后我自己会怎样?我已经开始采用这两种方法,但到目前为止还没有任何效果。

我采用这些方法是否走在正确的道路上,或者还有其他建议吗?

更新

我现在已切换为使用 v2.0 API,并设置了一个使用 MSAL 的新应用程序(位于 apps.dev.microsoft.com)。在应用程序端和 microsoft_v2_auth在 rails 一侧。当我从应用程序端的 MSAL 获取访问 token 后,我会将其发送到 POST 正文中的 Rails 服务器(通过 HTTPS)。在服务器端,我只是使用从应用程序获得的 token 作为授权 header 中的不记名 token ,在单独的操作(与 Omniauth 提供程序无关)中针对 Graph API“me”端点执行 GET。如果返回时没有错误,我会创建用户(如果用户不存在),然后将其登录,或者如果存在则仅登录。这似乎有效。

我只是使用 Omniauth 提供商进行网络登录。

那么!这种方法看起来合理吗?除了对用户进行身份验证之外,我确实不需要 Azure AD 中的任何内容。使用我从应用程序获得的 token 从 Graph API 发出 GET 请求似乎是最简单的方法?还有其他想法或担忧吗?

最佳答案

由于有人要求我对此进行更深入的了解,因此我将继续发布我最终实现的解决方案。

将其添加到您的 gemfile 中:

gem 'omniauth-microsoft_v2_auth'

将其添加到 config/devise.rb 文件的底部:

config.omniauth :microsoft_v2_auth, ENV['CLIENT_ID'], ENV['CLIENT_SECRET']

您必须将这些环境变量添加到您的环境中。我通常在开发时使用 Figaro gem,然后在部署时通过 Heroku CLI 设置它们。

您需要通过 session Controller 将用户路由到 Azure 身份验证。将其添加到您的routes.rb 文件中:

devise_for :users, :controllers => {sessions: 'sessions', registrations: 'registrations', omniauth_callbacks: "callbacks"} 

devise_scope :user do
  post 'users/sign_in_with_azad_token' => 'sessions#sign_in_with_azad_token'
end

以下是我在 session Controller 中实现操作的方法:

def sign_in_with_azad_token
    token = params[:token]

    # Use the graph API to ensure this user is legit
    uri = URI("https://graph.microsoft.com/v1.0/me/")
    request = Net::HTTP::Get.new(uri.request_uri)
    request['authorization'] = "Bearer #{token}"

    response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
        http.request(request)
    end

    json = JSON.parse(response.body)

    if json["error"].nil?
        # If no error, user was found
        user = User.from_uid_email(json["id"], json["userPrincipalName"])
        unless user.nil?
            sign_in("user", user)
            respond_to do |format|  
                format.json {  return render :json => {  :success => true, :user => user } }  
            end
        else
            respond_to do |format|  
                format.json {  return render :json => {  :success => false, :message => "You must sign in before continuing" }, status: :unauthorized }  
            end
        end

    else
        respond_to do |format|  
            format.json {  return render :json => {  :success => false, :message => json["error"]["message"]}, status: :unauthorized }  
        end
    end

end

您可能希望有一种方法允许您的用户在 Webi 浏览器中使用 Microsoft Azure 进行身份验证。在这种情况下,您需要将其添加到您的 Devise 新注册 View 中(我的位于views/devise/registrations/new.html.erb和views/devise/shared/_links.html.erb中):

    <%- if devise_mapping.omniauthable? %>
      <%- resource_class.omniauth_providers.each do |provider| %>
        <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
      <% end -%>
    <% end -%>

最后,我的客户端应用程序执行登录的端点位于 ...[server_url]/users/sign_in_with_azad_token.json

在应用程序端使用 MSAL iOS 框架进行身份验证并获取 token 后,我到达了此端点。我将 token 包含在作为请求正文一部分的 JSON 负载中。有效负载很简单:

{
    "token" : "dj9hs0shgkshd93hs92bh7493"

}

希望这有帮助。我已经有一段时间没有从事这方面的工作了,所以我可能忘记了一些事情。如果似乎缺少任何内容,请对此答案添加评论。

关于ios - 具有 Web + iOS 应用程序身份验证的 Rails Azure Active Directory SSO,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50080115/

相关文章:

ios - 在主应用程序窗口中显示警报 Controller ?

ios - SwiftUI 如何实现暗模式切换并刷新所有 View

ios - 在最初被拒绝后,我如何获得隐私权限以重新出现?

ruby-on-rails - Heroku 在远程应用程序上运行 rake?

ruby - 线程内的ActiveRecord太慢

ruby - ruby 的持续时间

c - iOS:将对象添加为属性监听器时,是否必须在释放对象之前将监听器设置为 "unregister"?

ruby-on-rails - LinkedIn OAuth 返回不明确的错误

ruby-on-rails - 我无法将投票结果四舍五入到 100%

ruby - 如何找到我的 Ruby 程序运行在哪个操作系统上?