c # asp.net mvc MSAL AcquireTokenSilentAsync завершается ошибкой через 45 минут - PullRequest
1 голос
/ 06 марта 2019

Я использую единый вход OAuth и O365 в своем веб-приложении. При запуске приложения пользователю предлагается войти в систему с помощью единого входа. Получение токена работает и вход выполнен успешно. После входа в систему пользователь взаимодействует с Graph с помощью графического клиента, который создает приложение ConfidentialClientApplication и получает доступ к хранилищу токенов сеанса. Это тоже хорошо работает. Но через 45 минут или час тот же самый клиентский вызов не удается. В хранилище токенов есть объект, но когда CCA вызывает GetAccountsAsync (), он всегда возвращает 0, поэтому сбой AcquireTokenSilentAsync. Не удалось ли сохранить некоторую соответствующую информацию в хранилище токенов? Что я здесь не так делаю и как мне это исправить? Я попытался повторно выполнить вызов и затем снова обратиться к хранилищу токенов, но результат тот же: несмотря на наличие объекта в хранилище, GetAccountsAsync возвращает 0 учетных записей.

Мне интересно, связано ли это с примерами из TokenStore, на которых я основывался. Я пытался сохранить токен в Session и в Cache, и они оба работают, когда пользователь впервые проходит аутентификацию, но в какой-то момент что-то происходит, что делает их недействительными при последующих запросах.

Из Startup.Auth.cs:

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

        app.UseCookieAuthentication(new CookieAuthenticationOptions() { CookieSecure = CookieSecureOption.Never, CookieName = "AppCookie", ExpireTimeSpan = TimeSpan.FromDays(7) });

        app.UseOpenIdConnectAuthentication(
            new OpenIdConnectAuthenticationOptions
            {
                ClientId = clientId,
                Authority = authority,
                PostLogoutRedirectUri = postLogoutRedirectUri,
                ResponseType = OpenIdConnectResponseType.CodeIdToken,
                TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuer = false,
                    RoleClaimType = "roles",
                    NameClaimType = "upn"
                },
                UseTokenLifetime = true,
                RedirectUri = postLogoutRedirectUri,
                Scope = "openid profile offline_access " + graphScopes,

                Notifications = new OpenIdConnectAuthenticationNotifications()
                {
                    RedirectToIdentityProvider = (context) =>
                    {

                        string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
                        context.ProtocolMessage.RedirectUri = appBaseUrl;
                        context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
                        return Task.FromResult(0);
                    },

                    AuthorizationCodeReceived = OnAuthorization,
                    AuthenticationFailed = OnAuthenticationFailed
                }
            });
    }

    private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
    {
        context.OwinContext.Response.Redirect("/Home/Error?message=" + context.Exception.Message);
        return Task.FromResult(0);
    }

    private async Task OnAuthorization(AuthorizationCodeReceivedNotification context)
    {
        var code = context.Code;
        string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;

        SessionTokenStore tokenStore = new SessionTokenStore(signedInUserID, context.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase);
        ConfidentialClientApplication cca = new ConfidentialClientApplication(clientId, postLogoutRedirectUri, new ClientCredential(appKey), tokenStore.GetMsalCacheInstance(), null);

        var accounts = await cca.GetAccountsAsync();

        try
        {
            AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, graphScopes.Split(' '));
        }
        catch (MsalException ex)
        {
            string message = "AcquireTokenByAuthorizationCodeAsync threw an exception";
            context.HandleResponse();
            context.Response.Redirect($"/Home/Error?message={message}&debug={ex.Message}");
        }
        catch (Microsoft.Graph.ServiceException ex)
        {
            string message = "GetUserDetailsAsync threw an exception";
            context.HandleResponse();
            context.Response.Redirect($"/Home/Error?message={message}&debug={ex.Message}");
        }
        catch (Exception ex)
        {

            throw ex;
        }
    }

Получение клиента Graph:

 private static GraphServiceClient GetAuthenticatedClient()
    {
        try
        {
            return new GraphServiceClient(
        new DelegateAuthenticationProvider(
            async (requestMessage) =>
            {
                string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
                SessionTokenStore tokenStore = new SessionTokenStore(signedInUserID, new HttpContextWrapper(HttpContext.Current));

                ConfidentialClientApplication cca = new ConfidentialClientApplication(appId, redirectUri.ToString(), new ClientCredential(appSecret), tokenStore.GetMsalCacheInstance(), null);

                var accounts = await cca.GetAccountsAsync();

                try
                {
                    var result = await cca.AcquireTokenSilentAsync(graphScopes.Split(' '), accounts.FirstOrDefault(), null, true);
                    requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
                }
                catch (MsalUiRequiredException ex)
                {

                    if (ex.ErrorCode == MsalUiRequiredException.UserNullError)
                    {
                        new HttpContextWrapper(HttpContext.Current).GetOwinContext().Authentication.Challenge(
                            new AuthenticationProperties { RedirectUri = redirectUri }, OpenIdConnectAuthenticationDefaults.AuthenticationType);

                        var account = await cca.GetAccountAsync(signedInUserID);

                        var result = await cca.AcquireTokenSilentAsync(graphScopes.Split(' '), account, null, true);
                        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
                    }
                    else
                    {
                        throw ex;
                    }
                }
            }));
        }
        catch (Exception e)
        {

            throw e;
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...