5

У меня есть консольное приложение, зарегистрированное в Azure AD, которое подключается к CRM Online (настроено с использованием these steps). Он запрашивает веб-API.ADAL-аутентификация без приглашения на диалоговое окно

Приложение должно работать без взаимодействия с пользователем ... но, к сожалению, вызов AcquireTokenSilentAsync всегда терпит неудачу и работает только AcquireTokenAsync. В результате появляется диалоговое окно входа пользователя, которое не отвечает требованиям пользователя!

Есть ли способ до предотвратить это приглашение, либо путем сохранения имени пользователя на компьютере-клиенте (который до сих пор не работал), либо, возможно, с использованием сертификата (но как вы это делаете?) Или что-то еще еще?

Я использую выпуск ADAL для .NET v3.10.305110106. Следующий код используется для проверки подлинности:

private static async Task PerformOnlineAuthentication() 
{ 
    _authInfo = new AuthInfo(); // This is just a simple class of parameters 

    Console.Write("URL (include /api/data/v8.x): "); 
    var url = Console.ReadLine(); 

    BaseUri = new Uri(url); 
    var absoluteUri = BaseUri.AbsoluteUri; 
    _authInfo.Resource = absoluteUri; 

    Console.Write("ClientId: "); 
    var clientId = Console.ReadLine(); 
    _authInfo.ClientId = clientId; 

    Console.Write("RedirectUri: "); 
    var redirectUri = Console.ReadLine(); 
    _authInfo.RedirectUri = new Uri(redirectUri); 

    var authResourceUrl = new Uri($"{_authInfo.Resource}/api/data/"); 
    var authenticationParameters = await AuthenticationParameters.CreateFromResourceUrlAsync(authResourceUrl); 

    _authInfo.AuthorityUrl = authenticationParameters.Authority; 
    _authInfo.Resource = authenticationParameters.Resource; 

    _authInfo.Context = new AuthenticationContext(_authInfo.AuthorityUrl, false); 
} 

private static async Task RefreshAccessToken() 
{ 
    if (!IsCrmOnline()) 
     return; 

    Console.WriteLine($"Acquiring token from: {_authInfo.Resource}"); 
    AuthenticationResult authResult; 
    try 
    { 
     authResult = await _authInfo.Context.AcquireTokenSilentAsync(_authInfo.Resource, _authInfo.ClientId); 
    } 
    catch (AdalSilentTokenAcquisitionException astae) 
    { 
     Console.WriteLine(astae.Message); 
     authResult = await _authInfo.Context.AcquireTokenAsync(_authInfo.Resource, _authInfo.ClientId, _authInfo.RedirectUri, new PlatformParameters(PromptBehavior.RefreshSession)); 
    } 

    HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken); 
} 
+0

привет, вы проверили этот https://github.com/Azure-Samples/active-directory-dotnet-native-headless? он имеет одно имя пользователя - pwd. – Aravind

ответ

5

Благодаря @aravind который указал на active-directory-dotnet-native-headless образец.

Образец содержит FileCache class, который наследует от Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache. Этот класс управляет кэшированием учетных данных для зашифрованного файла на диске. Это означает, что в первом запуске есть только одно приглашение, после чего учетные данные локально сохраняются.

Окончательные куски головоломки являются:

  1. Вызов другого конструктора подписи для инициализации AuthenticationContext с файлового кэша:

    _authInfo.Context = new AuthenticationContext(
        _authInfo.AuthorityUrl, false, new FileCache()); 
    
  2. Получение учетных данных от пользователя в Microsoft.IdentityModel.Clients.ActiveDirectory.UserPasswordCredential объекта (см TextualPrompt()method in the sample)

  3. Передача учетных данных на другой метод подписи для AcquireTokenAsync():

    authResult = await _authInfo.Context.AcquireTokenAsync(
        _authInfo.Resource, _authInfo.ClientId, userCredential); 
    
0

Если «приложение должно работать без взаимодействия с пользователем» использование ClientCredential потока, например:

public static string GetAccessTokenUsingClientCredentialFlow(Credential cred) {   

     AuthenticationContext ac = new AuthenticationContext(cred.Authority); 
     AuthenticationResult r = ac.AcquireTokenAsync(cred.ResourceId, new ClientCredential(cred.ClientId, cred.ClientSecret)).Result; 
     return r.AccessToken; 
    } 
Смежные вопросы