Получение информации о пользователе, если WebAPI аутентифицирован на основе учетных данных клиента

До появления Azure AD через веб-приложение и API были -

Пользователь вводит идентификатор и пароль в форму приложения -> пользователь входит в систему (Asp.net Identity) -> с теми же учетными данными, генерирует токен (grant_type=password) в WebAPI-> сохраняет этот токен как cookie для дальнейшего использования.

Теперь с Azure AD -

У меня есть сценарий, где я должен аутентифицировать пользователя с помощью Azure AD. Webapi в Azure передает JWT, содержащий зарегистрированную информацию о пользователе. Из этой информации я извлекаю электронную почту пользователя и заставляю свое веб-приложение войти в систему (Asp.net Identity).

Web App вызывает WebAPI для получения токена, поскольку я не могу передать пароль, поэтому мой вызов токена изменился на (grant_type = client_credentials). Тем не менее, я теряю информацию об отдельных пользователях, которые вошли в веб-API. Если я проверяю context.user, он указывает на уникальный идентификатор клиента вместо любого пользователя.

Я знаю, что это грязно, но требовалось использовать те же приложения для проверки подлинности Azure AD, а также для проверки подлинности на основе форм. Пожалуйста, предложите, если есть какой-либо более простой способ добиться этого.

Изменить: я использую Owin OAuth

Я использую одно и то же приложение для проверки подлинности с помощью формы и Azure AD. Однако недавно пришлось добавить механизм регистрации на уровне веб-API, который работает для локального приложения, которое регистрирует с использованием идентификатора пользователя / пароля. Но это не работает, если webapi выдает токен с учетными данными клиента. Я попытался передать имя пользователя в качестве параметра при проверке идентификатора клиента (в ValidateClientAuthentication) и войти в систему пользователя. однако webapi не может сохранить эту информацию пользователя.

2 ответа

Решение

Вот что я сделал, чтобы исправить мою проблему - вместо присвоения утверждений идентификатора для клиента, я сгенерировал идентификатор пользователя. (_username - это локальная переменная, которая получает назначенное значение в "ValidateClientAuthentication" из параметра. Я понимаю, что это может быть не идеальным способом, но теперь мое приложение теперь работает с проверкой подлинности форм, а также с Azure AD с использованием токенов JWT)

 public override async Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
        {
            var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

            ApplicationUser user = await userManager.FindByNameAsync(_userName);

            ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager, CookieAuthenticationDefaults.AuthenticationType);

            var ticket = new AuthenticationTicket(oAuthIdentity, null);

            context.Validated(ticket);
        }

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

Исходя из моего понимания, когда мы используем Azure AD в качестве поставщика удостоверений, мы используем протокол соединения OpenId для получения формы id_token Azure AD. OpenId connect также поддерживает гибридный поток для получения кода авторизации и id_token в одном запросе.

Если вы разрабатывали с MVC с компонентом OWIN, этот поток по умолчанию. Нам нужно только получить токен доступа с кодом авторизации (поток предоставления кода OAuth 2.0), возвращаемым Azure AD, для вызова веб-API, и для этого не требуется повторной регистрации пользователей. А чтобы получить токен с кодом авторизации, мы можем добавить уведомление, как показано ниже:

public void ConfigureAuth(IAppBuilder app)
{
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());

        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                ClientId = clientId,
                Authority = Authority,
                PostLogoutRedirectUri = redirectUri,
                RedirectUri = redirectUri,
                Notifications = new OpenIdConnectAuthenticationNotifications()
                {
                    //
                    // If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
                    //
                    AuthorizationCodeReceived = OnAuthorizationCodeReceived,
                    AuthenticationFailed = OnAuthenticationFailed
                }

            });
}

private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification context)
{
        var code = context.Code;

        ClientCredential credential = new ClientCredential(clientId, appKey);
        string userObjectID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
        AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectID));

        // If you create the redirectUri this way, it will contain a trailing slash.  
        // Make sure you've registered the same exact Uri in the Azure Portal (including the slash).
        Uri uri = new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path));

        AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(code, uri, credential, graphResourceId);
}

Полный пример кода для вызова веб-API из веб-приложения вы можете найти здесь.

Другие вопросы по тегам