Не удается выполнить проверку подлинности MobileServiceClient в серверной части Azure ASP.NET

У меня есть веб-приложение ASP.NET (.NET Framework) на основе шаблона Visual Studio 2019 с настраиваемой аутентификацией с отдельными учетными записями пользователей.

public void ConfigureAuth(IAppBuilder app)
{


           // Configure the db context and user manager to use a single instance per request
                app.CreatePerOwinContext(ApplicationDbContext.Create);
                app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

                // Enable the application to use a cookie to store information for the signed in user
                // and to use a cookie to temporarily store information about a user logging in with a third party login provider
                app.UseCookieAuthentication(new CookieAuthenticationOptions());
                app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

                // Configure the application for OAuth based flow
                PublicClientId = "self";
                OAuthOptions = new OAuthAuthorizationServerOptions
                {
                    TokenEndpointPath = new PathString("/Token"),
                    Provider = new ApplicationOAuthProvider(PublicClientId),
                    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                    AccessTokenExpireTimeSpan = TimeSpan.FromDays(10),
                    // In production mode set AllowInsecureHttp = false
                    AllowInsecureHttp = false
                };

                // Enable the application to use bearer tokens to authenticate users
                app.UseOAuthBearerTokens(OAuthOptions);
    }

Работает с Почтальоном. Я могу получить токен и контроллер доступа, помеченный как [Авторизовать]

Я борюсь с аутентификацией MobileServiceClient, который я использую для автономной синхронизации. Клиент инициализируется таким образом:

client = new MobileServiceClient(App.BackendUrl, new NativeMessageHandler());      

         public async Task LoginAsync(string username, string password)
                {
                    try
                    {

                        var token = await GetAuthenticationToken(username, password);

                        MobileServiceUser user = new MobileServiceUser(token.userName);

                        user.MobileServiceAuthenticationToken = token.Access_Token;

                        client.CurrentUser = user;

                    }
                    catch (InvalidGrantException) 
                    {
                        throw; 
                    }
                    catch (MobileServiceInvalidOperationException ex) 
                    { 
                        throw; 
                    }
                    catch (Exception ex)
                    {
                        Crashes.TrackError(ex);
                        Debug.WriteLine(ex);
                        throw;
                    }
                }

            private async Task<AuthenticationToken> GetAuthenticationToken(string username, string password)
            {
                var keyValues = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>("username", username),
                    new KeyValuePair<string, string>("password", password),
                    new KeyValuePair<string, string>("grant_type", "password")
                };

                HttpContent httpContent = new FormUrlEncodedContent(keyValues);
                httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

                try
                {

                    var response = await client.InvokeApiAsync("/token",
                                            httpContent,
                                            HttpMethod.Post,
                                            null,
                                            null);

                    return JsonConvert.DeserializeObject<AuthenticationToken>(await response.Content.ReadAsStringAsync());
                }
                catch (MobileServiceInvalidOperationException exception)
                {
                    if (string.Equals(exception.Message, "invalid_grant"))
                        throw new InvalidGrantException("invalid credentials",  exception);
                    else
                        throw;
                }
            } 

Вот код для тестирования:

    public async Task InitializeAsync()
            {
                if (client?.SyncContext?.IsInitialized ?? false)
                    return;
                // Create a reference to the local sqlite store
                const string path = "syncstore.db";

                var store = new MobileServiceSQLiteStore(path);

                // Define the database schema
                 store.DefineTable<Brand>(); brandTable = new AzureCloudTable<Brand>(client, null);

                // Actually create the store and update the schema
                try
                {
                    await client.SyncContext.InitializeAsync(store);
                }
                catch (Exception ex)
                {
                    Crashes.TrackError(ex);
                    Debug.WriteLine(ex);
                }
            }

            async Task Test(string username, string password)
            {
                await LoginAsync("Simulator8", " ");
                await InitializeAsync();

                //Test pull
                try
                {
                  await brandTable.PullAsync();
                }
                catch (Exception ex)
                {
                }
            }

Исключение при тестировании:

+ ex {Microsoft.WindowsAzure.MobileServices.MobileServiceInvalidOperationException: запрос не может быть выполнен. (Неавторизовано) в Microsoft.WindowsAzure.MobileServices.MobileServiceHttpClient.ThrowInvalidResponse (запрос System.Net.Http.HttpRequestMessage, ответ System.Net.Http.HttpResponseMessage) [0x001d2] в: 0 в Microsoft.Net.Http.HttpResponseMessage. .Net.Http.HttpClient client, запрос System.Net.Http.HttpRequestMessage, System.Boolean sureResponseContent, System.Threading.CancellationToken cancellationToken) [0x00121] в: 0 в Microsoft.WindowsAzure.MobileServiceHttp.BetleServices.MobileServiceHttp: , Метод System.Net.Http.HttpMethod, System.String uriPathAndQuery, пользователь Microsoft.WindowsAzure.MobileServices.MobileServiceUser, содержимое System.String, System.Boolean sureResponseContent, System.Collections.Generic.IDictionary2[TKey,TValue] requestHeaders, System.Threading.CancellationToken cancellationToken) [0x000f0] in <d385e67aff524dc7bd2d27425b9e81ae>:0 at Microsoft.WindowsAzure.MobileServices.MobileServiceTable.ReadAsync (System.String uriString, Microsoft.WindowsAzure.MobileServices.MobileServiceFeatures features) [0x0009c] in <d385e67aff524dc7bd2d27425b9e81ae>:0 at Microsoft.WindowsAzure.MobileServices.MobileServiceTable.ReadAsync (System.String query, System.Collections.Generic.IDictionary2. WindowsAzure.MobileServices.MobileServiceFeatures) [0x00136] в: 0 в Microsoft.WindowsAzure.MobileServices.Sync.PullAct ion.ProcessTableAsync () [0x00134] в: 0 в Microsoft.WindowsAzure.MobileServices.Sync.TableAction.ExecuteAsync () [0x00251] в: 0 в Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext.Exection Действие Sync.SyncAction) [0x00090] в: 0 в Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceSyncContext.PullAsync (System.String tableName, Microsoft.WindowsAzure.MobileServices.Sync.MobileServiceTableKind tableKring queryId, System.String queryId, System.String Параметры Microsoft.WindowsAzure.MobileServices.MobileServiceRemoteTableOptions, System.Collections.Generic.IDictionary2[TKey,TValue] parameters, System.Collections.Generic.IEnumerable1 [T] relatedTables, средство чтения Microsoft.WindowsAzure.MobileServices.MobileServiceObjectReader, System.Threading.CancecellllationMobileServiceObjectReader, Microsoft.Threading.CancecellllationTokull [en], Microsoft.Threading. ] в: 0

  1. Если я попытаюсь использовать токен, который я получаю в token.Access_Token в Postman, он работает
  2. Если я попробую выполнить синхронизацию с контроллером без [Авторизовать], все заработает.
  3. Это сообщение из потока журнала Azure:

* 2020-04-15 18:20:10 xxxBACKENDxxx POST / token X-ARR-LOG-ID = c0abefa4-8754-47e2-966d-add7716e6a95 443 - 000.000.000 ZUMO / 4.1 + (lang = Managed; + os = iOS ; + os_version = 13.3; + arch = MacOSX; + version = 4.1.2.0) - - xxxBACKENDxxx.azurewebsites.net 200 0 0 1825 1377 6312

2020-04-15 18:20:10 xxxBACKENDxxx GET / tables / Brand $ filter = (updatedAt% 20ge% 20datetimeoffset'2020-04-06T21% 3A05% 3A17.7200000% 2B00% 3A00 ') & $ orderby = updatedAt & $ skip = 0 & $ top = 50 & __ includeDeleted = true & X-ARR-LOG-ID = 287a5464-caad-43be-a3c5-25245e0f9f49 443 Simulator8 000.000.000 ZUMO / 4.1 + (lang = Managed; + os = iOS; + os_version = 13.3; + arch = MacOSX + версия = 4.1.2.0) ARRAffinity = 62f587f816224cc3b867889be38db42f5322e4bdb4b71703dac6a261166d1545 +. AspNet.Cookies = rpLpkcIS9jfvK1FyWL6q-2_5ImjYFR9yB1ZiIPd4iiTxHAGL5A0CFu4qihtFZmu-GKKQzVQ5hoxReQGQVpS7w2a0jnjvvFL4dpe_wS9_7nfTxMTBuDXiKDHGZBakbd28UR1CWvyq7iFDUI8AkKj1zrM2uYz93kpg1WMQCSx-Z3tREike74S3LqUOCnRuPjil-wMqOzDDDTJKL9JLQZ750MbQbT_-DLmj31qMa55emfGgUcSEM7I5ksMD2IIMvEeAEqwsp-XKyhp17utOTy5OepSqO8lxrGLng96GY-shVFBP4gDt7YP2bNS3RCtXkCWSOve4g7ckWDud8SAOk1KRpkj4k-B9ZogpAqc9Zuz0idTBruY3HZ3sTHCw__atnd8DQVwNQtEu8kX1Cz2WFbkO35GHOULA7TvKyGiJu-LOpf2-SZPoNl12lqH0jdvT1kI32WF2RDKbQ2W9eyWzURHOsUvekcg5EJOZUDEehXYfbo0 - xxxBACKENDxxx.azurewebsites.net 401 0 0 543 2837 46 *

Имя пользователя правильное. Но если я не вызываю GetAuthenticationToken из LoginAsync и не передаю токен пользователю вручную .MobileServiceAuthenticationToken, то результат будет следующим:

//var token = await GetAuthenticationToken(username, password);

MobileServiceUser user = new MobileServiceUser(username);

user.MobileServiceAuthenticationToken = "bearer _F-Bd8_74ZGV2gmKN4dkjPIRgZh7keYa-nIKpbjvSlfBV9wP2Reu9Z9Spy1eqK47LRdnXxKlMsZ5...
client.CurrentUser = user;

2020-04-15 18:15:34 xxxBACKENDxxx GET / tables / Brand $ filter = (updatedAt% 20ge% 20datetimeoffset'2020-04-06T21% 3A05% 3A17.7200000% 2B00% 3A00 ') & $ orderby = updatedAt & $ skip = 0 & $ top = 50 & __ includeDeleted = true & X-ARR-LOG-ID = c3bcf13e-b270-4d58-897f-58cfb9727e56 443 - 000.000.000. ZUMO / 4.1 + (lang = Managed; + os = iOS; + os_version = 13.3; + arch = MacOSX; + version = 4.1.2.0) - - xxxBACKENDxxx.azurewebsites.net 401 0 0 543 2249 4625

Кажется, что установка пользователя не имеет никакого эффекта.

Есть идеи, почему я не могу аутентифицировать свой MobileServiceClient?


person Miloslav Tauchman    schedule 15.04.2020    source источник


Ответы (1)


Я нашел здесь ответ https://devblogs.microsoft.com/xamarin/personalized-experiences-with-azure-mobile-apps-authentication/

В заголовке «Авторизация» необходимо отправить токен. Я создал класс, используемый для HttpMessageHandler

public class AuthHandler : DelegatingHandler
{
    public IMobileServiceClient Client { get; set; }
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (Client.CurrentUser != null)
            request.Headers.Add("Authorization", "bearer " + Client.CurrentUser.MobileServiceAuthenticationToken);
        return base.SendAsync(request, cancellationToken);
    }
}

Использую для инициализации клиента

var handlers = new AuthHandler();
client = new MobileServiceClient(App.BackendUrl, handlers);
handlers.Client = client;
person Miloslav Tauchman    schedule 19.04.2020