从控制台应用程序使用 Skype for Business Online 发送即时消息

Sending IM with Skype for Business Online from Console App

我正在尝试设置一个 C# 控制台应用程序,它可以从通用 AD 帐户通过 Skype for Business 在线向用户发送 notifications/reminders。前几天我很高兴地看到,根据此页面,UCWA 现在在 Skype for Business online 中受支持:https://msdn.microsoft.com/en-us/library/office/mt650889.aspx

我一直在尝试按照本教程进行设置:https://msdn.microsoft.com/en-us/library/office/mt590891(v=office.16).aspx。到目前为止,我真的没有太多运气......我在 Azure AD 中设置了我的应用程序,但我卡在了那篇文章的 "Requesting an access token using implicit grant flow" 步骤(不能 100% 确定我之前采取了正确的操作要么)...到目前为止我有这个:

        string clientId = "xxxxxxxx"
        string resourceUri = "https://webdir.online.lync.com";
        string authorityUri = "https://login.windows.net/common/oauth2/authorize";
        AuthenticationContext authContext = new AuthenticationContext(authorityUri);
        UserCredential cred = new UserCredential("username", "password");
        string token = authContext.AcquireToken(resourceUri, clientId, cred).AccessToken;


        var poolReq = CreateRequest("https://webdir.online.lync.com/autodiscover/autodiscoverservice.svc/root", "GET",token);
        var poolResp = GetResponse(poolReq);

        dynamic tmp = JsonConvert.DeserializeObject(poolResp);
        string resourcePool = tmp._links.user.href;

        Console.WriteLine(resourcePool);

        var accessTokenReq = CreateRequest("https://login.windows.net/common/oauth2/authorize"
            + "?response_type=id_token"
            + "&client_id=" + clientId
            + "&redirect_uri=https://login.live.com/oauth20_desktop.srf"
            + "&state=" + Guid.NewGuid().ToString()
            + "&resource=" + new Uri(resourcePool).Host.ToString()
            , "GET",token);
        var accessTokenResp = GetResponse(accessTokenReq);

我的 GetResponse 和 CreateRequest 方法:

    public static string GetResponse(HttpWebRequest request)
    {
        string response = string.Empty;

        using (HttpWebResponse httpResponse = request.GetResponse() as System.Net.HttpWebResponse)
        {
            //Get StreamReader that holds the response stream
            using (StreamReader reader = new System.IO.StreamReader(httpResponse.GetResponseStream()))
            {
                response = reader.ReadToEnd();
            }
        }

        return response;
    }



    public static HttpWebRequest CreateRequest(string uri, string method, string accessToken)
    {
        HttpWebRequest request = System.Net.WebRequest.Create(uri) as System.Net.HttpWebRequest;
        request.KeepAlive = true;
        request.Method = method;
        request.ContentLength = 0;
        request.ContentType = "application/json";
        request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken));

        return request;
    }

accessTokenResp 是一个办公室在线登录页面,而不是我前进所需的访问令牌...所以我被卡住了。我已经尝试了上述代码的很多变体。

我一直在网上搜索更多示例,但实际上找不到任何示例,尤其是因为 UCWA 对 Office 365 的支持是如此之新。有没有人有一个例子说明如何做我想做的事情或者可以指出一个例子?到目前为止,我发现的所有内容都与我正在尝试的还差得很远。不幸的是,我无法使用 Skype for Business 客户端 SDK,因为它不能满足我的所有要求。

我刚刚在博客上写了这个 using a start-to-finish example, hopefully it will help you. I only go as far as signing in, but you can use it with another post I've done on sending IMs using Skype Web SDK here(见第 13 天和第 14 天),将两者结合起来,应该可以正常工作。

-汤姆

中列出的步骤的帮助下,我使用 ADAL (v3) 找到了一个可行的解决方案 使用 Azure AD 进行身份验证

这里是步骤,涉及使用 ADAL 向 AAD 请求多个身份验证令牌

  • 在 Azure AD 中将您的应用程序注册为本机应用程序。
  • 执行自动发现以查找用户的 UCWA 根资源 URI。
    这可以通过在
    上执行 GET 请求来完成 GET https://webdir.online.lync.com/Autodiscover/AutodiscoverService.svc/root?originalDomain=yourdomain.onmicrosoft.com

  • 使用 ADAL
    在自动发现响应中请求 UCWA 根资源的访问令牌return 例如,您的根资源将位于 https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
    您必须从 AAD 获取资源 https://webdir0e.online.lync.com/

  • 的令牌
  • 使用从 ADAL 获得的不记名令牌对根资源执行 GET
    GET https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com

  • 这将 return,在用户资源中,应用程序资源的 URI,创建您的 UCWA 应用程序的位置。在我的例子中是:
    https://webpoolam30e08.infra.lync.com/ucwa/oauth/v1/applications
    然后驻留在另一个域中,因此不同的受众/资源,未包含在先前获得的身份验证令牌中

  • 从 AAD 为主池和应用程序资源所在的主机资源获取新令牌(https://webpoolam30e08.infra.lync.com 在我的例子中)

  • 通过使用从 ADAL

  • 获得的令牌对应用程序 URI 执行 POST 创建一个新的 UCWA 应用程序

瞧,您的 UCWA 应用程序已创建。我现在注意到的是只有很少的资源可用,excluding me / presence。因此可以检索用户的在线状态,但不能更改自己的在线状态。 不过,我已经能够取回我的个人笔记,并且可以使用以下资源:

  • 交流
  • 会议

给我一些代码:

执行流程获取和切换auth token的函数

public static async Task<UcwaApp> Create365UcwaApp(UcwaAppSettings appSettings, Func<string, Task<OAuthToken>> acquireTokenFunc)
{
    var result = new UcwaApp();
    result.Settings = appSettings;

    var rootResource = await result.Discover365RootResourceAsync(appSettings.DomainName);
    var userUri = new Uri(rootResource.Resource.GetLinkUri("user"), UriKind.Absolute);
    //Acquire a token for the domain where user resource is
    var token = await acquireTokenFunc(userUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped));
    //Set Authorization Header with new token
    result.AuthToken = token;
    var usersResult = await result.GetUserResource(userUri.ToString());
    //
    result.ApplicationsUrl = usersResult.Resource.GetLinkUri("applications");
    var appsHostUri = new Uri(result.ApplicationsUrl, UriKind.Absolute).GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
    //Acquire a token for the domain where applications resource is
    token = await acquireTokenFunc(appsHostUri);
    //Set Authorization Header with new token
    result.AuthToken = token;
    //
    var appResult = await result.CreateApplicationAsync(result.ApplicationsUrl, appSettings.ApplicationId, appSettings.UserAgent, appSettings.Culture);

    return result;
}

使用 ADAL 检索 OAuth 令牌的用法代码

var ucSettings = new UcwaAppSettings
{
    UserAgent = "Test Console",
    Culture = "en-us",
    DomainName = "yourdomain.onmicrosoft.com",
    ApplicationId = "your app client id"
};

var acquireTokenFunc = new Func<string, Task<OAuthToken>>(async (resourceUri) =>
{
   var authContext = new AuthenticationContext("https://login.windows.net/" + ucSettings.DomainName);

   var ar = await authContext.AcquireTokenAsync(resourceUri,
                ucSettings.ApplicationId,
                new UserCredential("myusername", "mypassword"));


   return new OAuthToken(ar.AccessTokenType, ar.AccessToken, ar.ExpiresOn.Ticks);
});

var app = await UcwaApp.Create365UcwaApp(ucSettings, acquireTokenFunc);

当然应该可以避免使用 ADAL hard-coding 用户名和密码,但这对于 PoC 来说更容易,尤其是在您询问的控制台应用程序的情况下

我想他们今天才打开这个功能 - 我正在做一些与 Skype Web SDK 示例无关的事情,不得不创建一个新的 Azure AD 应用程序,并注意到有两个新的预览功能用于接收对话更新和更改用户信息。

现在 Github 示例中的所有内容都适用于 Skype For Business Online。

与 Massimo 的解决方案类似,我创建了 a Skype for Business Online C# based console app 来演示如何签署和使用 UCWA 来 create/list/delete 会议和更改用户状态。我还没有开始扩展它来发送 IM,但当然欢迎您克隆我的存储库并将其扩展到您的需要。只需将您的 Azure AD 租户名称和本机应用程序 ID 放入代码中。