我目前只能开发我的服务。服务的用户使用前端胖客户端并连接到我的Rest Service。它们将通过NTLM进行认证。
由于我的服务呼叫其他服务,因此该服务会模拟每个外部呼叫。
在某个时候,服务会发送一封电子邮件。在我的公司中,我们使用Active Directory。该服务在具有访问权的用户和邮箱下运行。服务不应提示登录或类似的内容。
现在,我正尝试通过Microsoft.Graph API发送邮件。但是我找不到任何发送邮件的方法。我总是遇到一些错误。
我得到的最后一个错误是:
当前已认证的上下文对此请求无效。当对需要用户登录的端点发出请求时,就会发生这种情况。例如,/ me需要登录的用户。代表用户获取令牌以向这些端点发出请求。将OAuth 2.0授权代码流用于移动和本机应用程序,并将OAuth 2.0隐式流用于单页Web应用程序。
这似乎“确定”。因为我仍然是假冒的。但是,如何恢复模拟?或者如何代表我发送邮件?
在我的设置下面:
private const string Authority = "https://login.microsoftonline.com/common";
internal const string ClientId = "MyClientID";
internal const string AppSecret = "MyAppSecret";
private static readonly TokenCache TokenCache = new TokenCache();
public void SendMail(string recipients, string subject, string body, string attachments, bool sendAsHtml)
{
this._log.Information($"Trying to send Mail with Subject {subject} to {recipients}...");
var mailRecipients = this.GetRecipients(recipients);
var mailAttachments = this.GetAttachments(attachments);
var mail = this.CreateMail(mailRecipients, subject, body, mailAttachments, sendAsHtml);
var graphClient = this.GetAuthenticatedClient();
// Tried to send "OnBehalf" but didn't work:
//var mailRequestBuilder = graphClient.Users["ServiceUserName"].SendMail(mail, true);
var mailRequestBuilder = graphClient.Me.SendMail(mail, true);
var sendMailRequest = mailRequestBuilder.Request();
sendMailRequest.PostAsync().GetAwaiter().GetResult();
this._log.Information($"Successful send Mail with Subject {subject} to {recipients}.");
}
private Message CreateMail(IEnumerable<Recipient> mailRecipients, string subject, string body, IMessageAttachmentsCollectionPage mailAttachments, bool sendAsHtml)
{
return new Message
{
ToRecipients = mailRecipients,
Subject = subject,
Body = new ItemBody
{
Content = body,
ContentType = sendAsHtml ? BodyType.Html : BodyType.Text
},
Attachments = mailAttachments
};
}
private IMessageAttachmentsCollectionPage GetAttachments(string attachments)
{
var list = new MessageAttachmentsCollectionPage();
var attachmentList = attachments?.Split(';');
if (attachmentList.IsNullOrEmpty())
return list;
foreach (var attachment in attachmentList)
{
if (File.Exists(attachment))
list.Add(this.CreateAttachment(attachment));
}
return list;
}
private FileAttachment CreateAttachment(string attachmentPath)
{
return new FileAttachment
{
ODataType = "#microsoft.graph.fileAttachment",
ContentBytes = File.ReadAllBytes(attachmentPath),
Name = Path.GetFileName(attachmentPath),
};
}
private IReadOnlyCollection<Recipient> GetRecipients(string recipients)
{
if (string.IsNullOrWhiteSpace(recipients))
throw new ArgumentNullException(nameof(recipients), "No recipient specified.");
var recipientList = (from rec in recipients.Split(';')
let recipient = rec.Trim()
where !string.IsNullOrEmpty(recipient)
select CreateRecipient(recipient)).ToArray();
if (recipientList.Length == 0)
throw new ArgumentNullException(nameof(recipients), "No recipient specified.");
return recipientList;
}
private static Recipient CreateRecipient(string recipient)
{
return new Recipient
{
EmailAddress = new EmailAddress
{
Address = recipient
}
};
}
private GraphServiceClient GetAuthenticatedClient()
{
var graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(AuthenticateGraphClientAsync));
return graphClient;
}
private static Task AuthenticateGraphClientAsync(HttpRequestMessage request)
{
return Task.Run(() =>
{
var accessToken = GetAccessToken();
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
});
}
private static string GetAccessToken()
{
var authContext = new AuthenticationContext("https://login.windows.net/common/", TokenCache);
var credentials = new ClientCredential(ClientId, AppSecret);
var authResult = authContext.AcquireTokenAsync("https://graph.microsoft.com/", credentials).GetAwaiter().GetResult();
return authResult.AccessToken;
}
有人知道我的服务如何发送电子邮件吗?它可以是服务用户,请求用户,也可以是OnBehalf。那不重要。
//编辑
我现在终于解决了。我现在使用以下Windows身份验证
private static async Task<string> GetAccessTokenAsync()
{
var authContext = new PublicClientApplication(ClientId, Authority, TokenCache);
var authResult = await authContext.AcquireTokenByIntegratedWindowsAuthAsync(ApplicationScopes);
return authResult.AccessToken;
}