我需要让用户从 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/