2015-09-16 52 views
3

基本上,我正在为我们为我们制作的员工门户实施SSO,但我也希望能够访问图形API(至少,AzureAD REST API项目,如添加/删除/获取用户信息),而无需通过SSO登录。如何在没有单一登录的情况下使用Azure AD

这样,我可以使用我正在考虑的某种API密钥/秘密种类的设置和计划与某些方式与AD进行交互的cron作业。从技术上讲,我可以登录并设置我的账户为运行此账户的账户,但这看起来有点不可靠(例如,如果我的账户出现问题,密码过期,更改等等,那么刷新令牌将不再是有效的,我将不得不再次登录,任务可能会暂时中断。)

我可以发誓我在几个月前正在考虑实施此操作时看到过有关此文档,但我不能为我现在的生活找到它。

真的希望这不是重复的,我只是不能想到的措辞搜索,不会提供基于SSO的API信息。

更新 - 好吧,它看起来像我想通了这一点(与肖恩Luttin的答案的帮助下贴:https://stackoverflow.com/a/32618417/3721165 [链接为了方便])

所以,所有的信息肖恩汇聚真的很有帮助。最初这些文档由于他们如何说词而相当混乱,以及其中一些例子的复杂性。但是,一旦我通过一些例子挖掘,再加上一些肖恩提供的信息,并以我个人的一些试验/研究的,我能想出这个(基本演示/概念):

using System; 
using System.Globalization; 
using System.Threading.Tasks; 

using Microsoft.IdentityModel.Clients.ActiveDirectory; 
using Microsoft.Azure.ActiveDirectory.GraphClient; 


namespace AzureADGraphApi 
{ 
    class Program 
    { 
     private static string tenant = "...tenant id..."; 
     private static string clientid = "...client id..."; 
     private static string appkey = "...app key..."; 
     private static string aadinstance = "https://login.microsoftonline.com/{0}"; 
     private static string graphResourceUrl = "https://graph.windows.net"; 

     static void Main(string[] args) 
     { 
      Uri serviceRoot = new Uri(graphResourceUrl + "/" + tenant); 
      ActiveDirectoryClient adc = new ActiveDirectoryClient(serviceRoot, async() => await GetToken()); 

      IPagedCollection<IUser> Users = adc.Users.ExecuteAsync().Result; 

      bool pagesLeft = false; 
      do 
      { 
       foreach (IUser user in Users.CurrentPage) 
       { 
        Console.WriteLine(user.DisplayName); 
       } 
       pagesLeft = Users.MorePagesAvailable; 
       Users = Users.GetNextPageAsync().Result; 
       Console.WriteLine("--- Page Break ---"); 
      } while (pagesLeft); 
      Console.ReadLine(); 
     } 

     private static async Task<string> GetToken() 
     { 
      AuthenticationContext authContext = new AuthenticationContext(String.Format(CultureInfo.InvariantCulture, aadinstance, tenant)); 
      AuthenticationResult result = authContext.AcquireToken(graphResourceUrl, new ClientCredential(clientid, appkey)); 
      return result.AccessToken; 
     } 
    } 
} 

我通过进一步的研究发现,为了按照我的意图使用图形API,您必须将图形资源URL(https://graph.windows.net)提供给AquireToken方法,而不是您的应用程序ID/URL。

所以,我接受肖恩的答案,但我也想给我的答案的工作结果。

感谢您的帮助,伙计们!

+0

是你想以编程方式或仅通过用户界面来执行此操作?如果您正在寻找仅用户界面解决方案,那么您最好在ServerFault或非编程论坛上提问。 –

+2

@ShaunLuttin编程。我基本上需要编写一个服务来执行(最好在PHP中使用一个),以便在AzureAD用户和其他各种事情上维护一些自定义信息。我也看到了你的回答,但我实际上只是回家过夜(5:03在这里,耶!),所以明天早上我会检查一下。谢谢btw! –

回答

16

你需要的是无单点登录,做一个访问令牌。 Rick Rainey提供的链接将帮助你开始。

您可以通过调用AcquireTokenAsync以编程方式获取访问令牌。有很多方法可以调用AcquireTokenAsync,具体取决于您构建的应用程序类型以及您希望如何进行身份验证。您将需要决定是创建本机客户端应用程序还是创建Web应用程序。

Web Application or Native Client Application

基于应用程序类型,以认证方式不同的公平量。这听起来像你想在没有用户提示的情况下进行身份验证(即不要求输入用户名/密码)。以下内容适用于我,并且根本不涉及用户提示。他们每个人都使用以下常量,您需要从manage.windowsazure.com门户获取这些常量。如果你需要帮助找到他们中的任何一个,请在评论中告诉我。

private const string 

    DIRECTORY_TENANT_NAME = "mytenant.onmicrosoft.com", 
    DIRECTORY_TENANT_ID = "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx", 
    RESOURCE_URL = "https://graph.windows.net", 
    SUBSCRIPTION_ID = "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx", 
    AUTHORITY = "https://login.microsoftonline.com/" + DIRECTORY_TENANT_NAME, 

    // web application 
    CLIENT_ID_WEB = "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx", 
    CLIENT_SECRET_WEB = "xxxxxxxx/xxxxxxxxxxxx/xxxxxxxx/xxxxxxxx=", 

    // native client application 
    CLIENT_ID_NATIVE = "xxxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx", 

    // adminstrator 
    USER_NAME = "[email protected]", 
    USER_PASSWORD = "xxxxxxxxxx"; 

现在下面的三个选项向您(尽管可能有其他人)打开以获取令牌。我已经测试了以下每一项,只要您已正确配置Azure Active Directory租户,用户和应用程序,它们都可以工作。

AcquireToken(字符串资源,ClientAssertionCertificate clientCertificate)适用于Web Apps。这种方法的缺点是最初设置比较困难(PowerShell,证书创建)。好处是一旦安装它很容易使用。随着本地客户机App它不工作,并抛出这个错误:AADSTS50012: Client is public so a 'client_assertion' should not be presented.

var authContext = new AuthenticationContext(AUTHORITY); 
var store = new X509Store(StoreLocation.CurrentUser); 
store.Open(OpenFlags.ReadOnly); 
var certs = store 
    .Certificates 
    .Find(X509FindType.FindByIssuerName, "mvp2015", false); 
var clientCertificate = new ClientAssertionCertificate(CLIENT_ID_WEB, certs[0]); 
var result = authContext 
    .AcquireTokenAsync(RESOURCE, clientCertificate) 
    .Result; 

AcquireToken(字符串资源,ClientCredential clientCredential)作品与Web应用程序。安装更容易,安装后易于使用。本机客户端应用程序不支持这种方法,因为它们缺少客户端密钥。

var authContext = new AuthenticationContext(AUTHORITY); 
var clientCredential = new ClientCredential(CLIENT_ID_WEB, CLIENT_SECRET_WEB); 
var result = authContext 
    .AcquireTokenAsync(RESOURCE, clientCredential) 
    .Result; 

AcquireToken(字符串资源,字符串的clientId,UserCredential userCredential)作品通过Native Client应用程序。 Web应用程序失败并出现此错误:AADSTS90014: The request body must contain the following parameter: 'client_secret or client_assertion'.一个问题是,您登录的用户必须在Active Directory中正确配置。

var authContext = new AuthenticationContext(AUTHORITY); 
var userCredential = new UserCredential(USER_NAME, USER_PASSWORD); 
var result = authContext 
    .AcquireTokenAsync(RESOURCE, CLIENT_ID_NATIVE, userCredential) 
    .Result; 

一旦你用你喜欢的方式令牌,然后你可以使用Active Directory图这个样子。为了可读性,它在Func中,尽管您可以将accessTokenGetter置入其自己的方法中。

Func<Task<string>> accessTokenGetter = async() => 
{ 
    var authContext = new AuthenticationContext(AUTHORITY, false); 
    var clientCredential = new ClientCredential(CLIENT_ID_WEB, CLIENT_SECRET_WEB); 
    var result = await authContext 
     .AcquireTokenAsync(RESOURCE_URL, clientCredential); 
    var token = result.AccessToken; 
    return token; 
}; 

var uriRoot = new Uri(RESOURCE_URL); 
var uriTenant = new Uri(uriRoot, DIRECTORY_TENANT_ID); 
var client = new ActiveDirectoryClient(uriTenant, accessTokenGetter); 
foreach (var u in client.Users.ExecuteAsync().Result.CurrentPage) 
{ 
    var n = u.DisplayName; 
} 

备注

  • DIRECTORY_TENANT_ID是在Web浏览器的地址栏,当我们在我们的Azure中的Active Directory租户的仪表板。 manage.windowsazure.com> Active Directory>一些租户。
  • 一旦我们在Azure Active Directory中创建了我们的应用程序,我们需要配置其权限。这是我们的应用程序配置选项卡的底部。 manage.windowsazure.com> Active Directory>一些租户>应用程序>一些应用程序>配置。
  • 上面所用的演示2个的NuGet包:
    • Microsoft.Azure.ActiveDirectory.GraphClient版本2.1.0
    • Microsoft.IdentityModel.Clients.ActiveDirectory版本2.19.208020213

此外

看到这里有一个例子: https://github.com/AzureADSamples/ConsoleApp-GraphAPI-DotNet

+1

嘿,感谢您的详细写作!我会仔细研究这一切。你碰巧知道在PHP的一面有没有办法做到这一点?我知道C#.net,所以这不是写在C#中的问题(最终整个事情将是asp.net,当vnext出来时)。无论如何,这不是一个大问题,我想我需要在这里运行它。门户将在云中,但后台服务将在这里,因为我们所有的系统都在这里,我会通过安全的API将信息推送到门户网站进行缓存。 –

+1

阅读它,要清楚:“AcquireToken(字符串资源,ClientCredential clientCredential)”我是否需要在运行时提供每次运行的凭据,或者我可以在第一次执行此操作(例如在部署的服务器上初始设置应用程序)和它(或Windows)缓存访问令牌?然后,其次,如果它确实缓存了他们有多长时间的文档?谢谢! –

+0

是的。应用程序默认缓存访问令牌,并将它们保存在内存中。 https://msdn.microsoft.com/en-us/library/microsoft.identitymodel.clients.activedirectory.tokencache.defaultshared.aspx –

相关问题