Я столкнулся со следующей ситуацией: у меня есть две регистрации приложений в Azure AD — веб-приложение Angular 17 и REST API с .NET 6. Я настроил аутентификацию/авторизацию через Azure AD. Приложение Angular вызывает API с токеном доступа через MSAL, и все работает как задумано.
Недавно я расширил свой API клиентом Graph, чтобы составить электронное письмо Outlook и вернуть ссылку, которую Angular может использовать для открытия Outlook и отображения электронного письма.
Затем пользователь может просмотреть, вручную настроить и отправить электронное письмо. Для этого я расширил регистрацию приложения API в Azure, добавив область «Mail.ReadWrite» и реализовав ее на C# следующим образом:
string clientId = _configuration["AzureAd:ClientId"];
string clientSecret = _configuration["AzureAd:ClientSecret"];
string tenantId = _configuration["AzureAd:TenantId"];
string[] scopes = { "Mail.ReadWrite" };
var options = new OnBehalfOfCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzurePublicCloud };
var onBehalfOfCredential = new OnBehalfOfCredential(tenantId, clientId, clientSecret, userAccessToken, options);
var graphClient = new GraphServiceClient(onBehalfOfCredential, scopes);
var requestBody = new Message
{
Subject = $"Test",
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "Sehr geehrte Damen und Herren,<br/><br/>" +
"Test"
},
ToRecipients = new List<Recipient>
{
new() { EmailAddress = new EmailAddress { Address = sendDocumentsRequest.Receiver } }
},
From = new Recipient { EmailAddress = new EmailAddress { Address = sendDocumentsRequest.Sender } }
};
// 1. Step: Create E-Mail in drafts folder
var resultMessage = await graphClient.Me.Messages.PostAsync(requestBody);
и это отлично работает для меня.
Однако все остальные пользователи получают следующее сообщение об ошибке:
2024-03-20 08:28:50.578 +01:00 [ERR] Ошибка при обработке документы с идентификатором сеанса XXXXX Azure.Identity.AuthenticationFailedException: OnBehalfOfCredential аутентификация не удалась: AADTS65001: Пользователь или администратор не выполнил согласился использовать приложение с идентификатором «XXXXXX» и именем «API_DEV». Отправьте интерактивный запрос авторизации для этого пользователя и ресурса. ---> MSAL.NetCore.4.59.0.0.MsalUiRequiredException: ErrorCode:valid_grant Microsoft.Identity.Client.MsalUiRequiredException: AADTS65001: Пользователь или администратор не дал согласия на использование приложение с идентификатором «XXXX» и именем «XXXX». Отправить интерактивный запрос авторизации для этого пользователя и ресурса. Microsoft.Identity.Client.Internal.Requests.RequestBase.HandleTokenRefreshErrorAsync(MsalServiceException) е, MsalAccessTokenCacheItem кэшированныйAccessTokenItem) в Microsoft.Identity.Client.Internal.Requests.OnBehalfOfRequest.ExecuteAsync(CancellationToken отменуToken) на Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken отменуToken) на Microsoft.Identity.Client.ApiConfig.Executors.ConfidentialClientExecutor.ExecuteAsync(AcquireTokenCommonParameters CommonParameters, AcquireTokenOnBehalfOfParameters onBehalfOfParameters, CancellationToken cancelToken) в Azure.Identity.AbstractAcquireTokenParameterBuilderExtensions.ExecuteAsync[T](AbstractAcquireTokenParameterBuilder`1 строитель, Boolean async, CancellationToken cancelToken) в Azure.Identity.MsalConfidentialClient.AcquireTokenOnBehalfOfCoreAsync(String[] области, строка tenantId, UserAssertion userAssertionValue, логическое значение EnableCae, Boolean async, CancellationToken cancelToken) в Azure.Identity.MsalConfidentialClient.AcquireTokenOnBehalfOfAsync(String[] области, строка tenantId, UserAssertion userAssertionValue, логическое значение EnableCae, Boolean async, CancellationToken cancelToken) в Azure.Identity.OnBehalfOfCredential.GetTokenInternalAsync(TokenRequestContext requestContext, Boolean async, CancellationToken cancelToken) Код статуса: 400
Они не получают запрос на согласие. Я не уверен, подтвердил ли я это согласие в модульном тесте. Пользователи, использующие приложение, распределяются по группам, связанным с приложением. Похоже, проблема связана с MSAL.NetCore.4.59.0.0.MsalUiRequiredException. Как я могу запрограммировать звонок по-другому? Как мне решить эту проблему?
=> AdminConsentRequired = нет => Документация Microsoft Learn.microsoft.com/de-de/graph/permissions-reference
Проверьте, помогает ли это stackoverflow.com/questions/72419373/…
@Sridevi Спасибо за ответ. Я добавил разрешения API.
They don't get a consent prompt. -> Это связано с добавлением нового разрешения API. Запрос согласия пользователя появится, когда пользователь, не соглашающийся, попытается войти в ваше приложение. Боюсь, вам следует попросить пользователей, у которых возникла эта проблема, выйти из системы и войти снова и посмотреть, появилось ли приглашение или нет. По сути, после того, как проблемные пользователи дадут согласие на использование приложения, они смогут нормально работать.
Если вы пытаетесь отправить почту, разрешение «Mail.ReadWrite» не будет работать. Вам необходимо назначить Mail.Send разрешение.
@sridevi: «Недавно я расширил свой API клиентом Graph, чтобы составить черновое электронное письмо Outlook и вернуть ссылку, которую Angular может использовать для открытия Outlook и отображения электронного письма. Затем пользователь может просмотреть, вручную настроить и отправить электронное письмо». => Область правильная и работает для меня как пользователя, но, как уже упоминалось, для других она не работает.
Не могли бы вы подтвердить, есть ли у вас какие-либо роли администратора в рамках арендатора?
@tiny wang: Вы уверены, что диалоговое окно отображается, хотя я ничего не менял в клиенте Angular, а вызов GraphClient происходит в API?"
в любом случае нам нужно попробовать, потому что вы не желаете давать согласие администратора, верно? А пока можем ли мы вызвать Graph API внутри приложения Angular?
@TinyWang Да, в моем случае согласие администратора давать не следует... Потому что пользователь должен вводить согласие индивидуально... И, по мнению Microsoft, это также должно быть по умолчанию (см. изображение, которое я добавил к запросу) = > Я предполагаю, что проблема в том, что этот диалог не может автоматически отображаться в Angular?
@TinyWang Я могу редактировать регистрацию приложения и иметь права администратора для нее, но не для организации.
Не могли бы вы подтвердить, включена ли эта опция в вашем клиенте i.imgur.com/qnkIZEt.png?
прежде всего, согласие пользователя должно работать в приложении Angular, однако, поскольку у вас разные регистрации приложений (mail.readwrite), разрешение API добавляется для приложения API, но не для входа в Angular, так что я' Я не уверен, повлияет ли это на запрос на получение гранта. Если вы уже протестировали это, но безуспешно, то, боюсь, у нас это не сработает. Возможно, мы можем попытаться использовать только одну регистрацию приложения, если согласие администратора для нас не вариант.
Другой вариант: давайте воспользуемся разрешением приложения, а затем воспользуемся контролем доступа на основе ролей, чтобы проверить, разрешено ли входящему запросу отправлять электронную почту.
@Sridevi да, он включен + Разрешить согласие владельца группы для всех владельцев групп. Все владельцы групп могут разрешать приложениям доступ к данным групп, которыми они владеют. Включено.
@Sridevi и tinyWang Спасибо за вашу поддержку. Теперь мы решили авторизовать всех пользователей через нашего администратора Azure, что сократило этот процесс. Впоследствии приложение Angular может открывать Outlook на основе вошедших в систему пользователей.





Теперь мы решили авторизовать всех пользователей через администратора, что сократило процесс. Впоследствии приложение может открывать Outlook на основе вошедших в систему пользователей.
Ошибка обычно возникает, если вы пропустили предоставление согласия на добавленное разрешение в API или клиентских приложениях.
Первоначально я тоже получил ту же ошибку, когда запустил тот же код, передав сгенерированный токен без предоставления согласия следующим образом:

Чтобы устранить ошибку, обязательно дайте согласие на добавленные разрешения либо в
App registration, либо вEnterprise application, где администратор проверит разрешения и предоставит их соответствующим образом.
В моем случае я предоставил согласие администратора на добавление разрешения в приложении API следующим образом:

Когда я запустил приведенный ниже код в своей среде после предоставления согласия, я получил такой ответ:
using Azure.Identity;
using Microsoft.Graph;
using Microsoft.Graph.Me.SendMail;
using Microsoft.Graph.Models;
namespace GraphSendMail
{
class Program
{
static async Task Main(string[] args)
{
try
{
string clientId = "appId";
string clientSecret = "secret";
string tenantId = "tenantId";
string userAccessToken = "token"; // Provide user access token here
string[] scopes = { "Mail.ReadWrite" };
var options = new OnBehalfOfCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzurePublicCloud };
var onBehalfOfCredential = new OnBehalfOfCredential(tenantId, clientId, clientSecret, userAccessToken, options);
var graphClient = new GraphServiceClient(onBehalfOfCredential, scopes);
var requestBody = new SendMailPostRequestBody
{
Message = new Message
{
Subject = "Test",
Body = new ItemBody
{
ContentType = BodyType.Html,
Content = "Sehr geehrte Damen und Herren,<br/><br/>" +
"Test"
},
ToRecipients = new List<Recipient>
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "[email protected]" // Provide recipient email here
}
}
},
CcRecipients = new List<Recipient>
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "[email protected]" // Provide cc email here
}
}
}
},
SaveToSentItems = true
};
await graphClient.Me.SendMail.PostAsync(requestBody);
Console.WriteLine("Email successfully sent.");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}
}
}
}
Ответ:

Чтобы убедиться в этом, я проверил то же самое в Outlook пользователя, где почта была успешно отправлена следующим образом:

Если вы предпочитаете, чтобы администратор авторизовал всех пользователей, проверив разрешения, вы можете проверить это Enterprise application следующим образом:

Не могли бы вы включить
API permissionsизображение портала ваших приложений, отредактировав свой вопрос?