从控制台应用程序使用 Skype for Business Online 发送 IM
Posted
技术标签:
【中文标题】从控制台应用程序使用 Skype for Business Online 发送 IM【英文标题】:Sending IM with Skype for Business Online from Console App 【发布时间】:2016-04-04 04:38:51 【问题描述】:我正在尝试设置一个 C# 控制台应用程序,该应用程序可以从通用 AD 帐户通过 Skype for Business Online 向用户发送通知/提醒。前几天我很高兴看到根据此页面,Skype for Business Online 现在支持 UCWA: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 中设置了我的应用程序,但我陷入了该文章的“使用隐式授权流请求访问令牌”步骤(不是 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,因为它不能满足我的所有要求。
【问题讨论】:
【参考方案1】:借助 Authentication using Azure AD 中概述的步骤,我使用ADAL (v3) 找到了一个可行的解决方案
此处的步骤涉及使用 ADAL 向 AAD 请求多个身份验证令牌
在 Azure AD 中将您的应用程序注册为本机应用程序。执行自动发现以查找用户的 UCWA 根资源 URI。
这可以通过在GET https://webdir.online.lync.com/Autodiscover/AutodiscoverService.svc/root?originalDomain=yourdomain.onmicrosoft.com
使用 ADAL 为自动发现响应中返回的 UCWA 根资源请求访问令牌
例如,您的根资源将位于
https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
您必须从 AAD 获取资源 https://webdir0e.online.lync.com/
使用从 ADAL 获得的不记名令牌对根资源执行 GETGET https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
这将在用户资源中返回应用程序资源的 URI,在哪里创建您的 UCWA 应用程序。在我的情况下是:https://webpoolam30e08.infra.lync.com/ucwa/oauth/v1/applications
然后驻留在另一个域中,因此不同的受众/资源,不包含在先前获得的身份验证令牌中
从 AAD 为主池和应用程序资源所在的主机资源获取新令牌(在我的情况下为 https://webpoolam30e08.infra.lync.com
)
使用从 ADAL 获得的令牌,通过对应用程序 URI 执行 POST 来创建新的 UCWA 应用程序
瞧,您的 UCWA 应用程序已创建。我现在注意到的是,只有很少的资源可用,不包括 me /存在。因此可以检索用户的存在状态,但不能更改自身的存在状态。 不过,我已经能够检索到我的个人笔记,并且可以使用以下资源:
人 通讯 会议给我看一些代码:
执行流程获取和切换认证令牌的功能
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 对用户名和密码进行硬编码,但这对于 PoC 来说更容易,尤其是在您要求的控制台应用程序的情况下
【讨论】:
当我为使用 ADAL 在自动发现响应中返回的 UCWA 根资源请求访问令牌时,卡在第 3 步,我收到以下错误:The application named https://webdir1a.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=xxxxx.onmicrosoft.com was not found in the tenant named xxxxx.onmicrosoft.com. This can happen if the application has not been installed by the administrator of the tenant or consented to by any user in the tenant.
我已注册本机 AAD 应用程序,并且正在使用正确的应用程序 ID...有什么想法吗?
确保您传递给 AcquireTokenAsync 的 URI 只是主机 URI(例如 https://webdir1a.online.lync.com
)。不得包含路径部分
谢谢。那是我的问题。我现在已经开始工作了。
这太棒了。希望他们能尽快改变自我存在。
:) 请投票支持officespdev.uservoice.com/forums/224641-general/suggestions/…【参考方案2】:
我刚刚写了一篇关于这个using a start-to-finish example 的博客,希望它会对你有所帮助。我只登录,但您可以将它与我在使用 Skype Web SDK here 发送即时消息的另一篇文章中使用(见第 13 天和第 14 天)并将两者结合起来,它应该可以正常工作。
-汤姆
【讨论】:
这是很好的信息,谢谢。但是,在我的情况下,我试图通过 C# 控制台应用程序直接使用用户 REST API 来完成此操作,而不是在浏览器中使用 javascript。【参考方案3】:与 Massimo 的解决方案类似,我创建了 a Skype for Business Online C# based console app,它演示了如何签署和使用 UCWA 来创建/列出/删除会议和更改用户状态。我还没有开始扩展它以发送即时消息,但当然欢迎您克隆我的存储库并将其扩展到您的需要。只需将您的 Azure AD 租户名称和本机应用 ID 放入代码中即可。
【讨论】:
【参考方案4】:我想他们今天才打开这个功能 - 我正在做一些与 Skype Web SDK 示例无关的事情,不得不创建一个新的 Azure AD 应用程序,并注意到有两个新的预览功能用于接收对话更新和更改用户信息.
现在 Github 示例中的所有内容都适用于 Skype For Business Online。
【讨论】:
以上是关于从控制台应用程序使用 Skype for Business Online 发送 IM的主要内容,如果未能解决你的问题,请参考以下文章
Office 添加或删除 skype for businessoneNoteOutLookoneDrive等功能
Office 添加或删除 skype for businessoneNoteOutLookoneDrive等功能
PowerBI从Lync或Skype for Business数据库中分析数据和KPI展现