401 Несанкционированный с Azure b2 c на Xamarin.Forms - PullRequest
0 голосов
/ 09 марта 2020

У меня есть приложение Xamarin.Forms, которое я использую для подключения к бэкэнду службы приложений, и я пытаюсь аутентифицироваться с помощью Auzre B2 C JWT токенов.

Через различные учебники, которые у меня есть удалось настроить B2 C с использованием учетных записей Microsoft, и я могу создавать пользователей, изменять пароли и генерировать токены доступа.

Следующим моим шагом было добавление атрибута [Authorize] в мой контроллер и попытка чтобы передать этот токен службе приложений и авторизовать пользователей, но независимо от того, что я пытаюсь, я получаю 401 несанкционированный ответ от моей службы.

  • Я добавляю токен JWT в заголовок авторизации моего HttpClient, и он попадает в сервис.
  • Я могу вставить свой токен в https://jwt.ms/, и он правильно сообщает мне, что находится в моем токене.
  • У меня есть реализован этот код в попытке выяснить, в чем дело.

ConfigureServices в файле startup.cs выглядит следующим образом:

public void ConfigureServices(IServiceCollection services) {

            services.AddAuthentication(options => {                
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
                .AddJwtBearer(options => {

                    options.Audience = Configuration["Authentication:AzureAd:ClientId"];

                    options.Events = new JwtBearerEvents {
                        OnAuthenticationFailed = AuthenticationFailed
                    };

                    options.Authority = $"https://{tenant name}.b2clogin.com/{tenant id}/{Configuration["Authentication:AzureAd:Policy"]}";

                    options.Events = new JwtBearerEvents {

                        OnAuthenticationFailed = ctx =>
                        {
                            ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
                            message += "From OnAuthenticationFailed:\n";
                            message += FlattenException(ctx.Exception);
                            return Task.CompletedTask;
                        },
                        OnChallenge = ctx =>
                        {
                            message += "From OnChallenge:\n";
                            ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
                            ctx.Response.ContentType = "text/plain";
                            return ctx.Response.WriteAsync(message);
                        },
                        OnMessageReceived = ctx =>
                        {
                            message = "From OnMessageReceived:\n";
                            ctx.Request.Headers.TryGetValue("Authorization", out var BearerToken);
                            if (BearerToken.Count == 0)
                                BearerToken = "no Bearer token sent\n";
                            message += "Authorization Header sent: " + BearerToken + "\n";
                            return Task.CompletedTask;
                        },
                        OnTokenValidated = ctx =>
                        {
                            Debug.WriteLine("token: " + ctx.SecurityToken.ToString());
                            return Task.CompletedTask;
                        }
                    };

                });

            services.AddMvc();
        }

Настройка выглядит следующим образом: * 1 023 *

        public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
            if (env.IsDevelopment()) {
                app.UseDeveloperExceptionPage();

                IdentityModelEventSource.ShowPII = true;
            } else {
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseAuthentication();
            app.UseMvc();
        }

И я также добавил этот вызов в AuthenticationFailed, поэтому я буду знать, работает ли моя аутентификация:


        Task AuthenticationFailed(AuthenticationFailedContext arg) {
            Console.WriteLine(arg.Exception.Message);
            return Task.FromResult(0);
        }

При моей текущей настройке я получаю Ошибка 401 с сервера, и это сразу после того, как оно попадает в событие OnChallenge, связанное с Startup.cs. Согласно ссылке выше, это то, что вызывается прямо перед тем, как он возвращает 401 пользователю, поэтому создается впечатление, что служба получает правильный токен и аутентифицируется, но, возможно, у меня не настроены правильные права?

Я не уверен, откуда go отсюда, но любые указания будут оценены.

Редактировать:

Как упоминалось в комментарии ниже, я смог свернуть мой сайт, используя токен доступа, сгенерированный после входа в систему через мое приложение, например:

curl https://mywebsite.azurewebsites.net/api/Values -i --header "Авторизация: Bearer [TOKEN]"

И это, похоже, работает без проблем, поэтому кажется, что это связано с тем, как я звоню контроллеру через мое приложение, а не через саму аутентификацию.

Редактировать 2 (решение):

Итак, что касается Правки 1, я был прав в том, что именно так я добавлял токен в заголовок авторизации. Это был не самый яркий момент, но я не звонил. Стоимость заявления, содержащего мой токен доступа. Я вызывал только .ToString () для самой заявки, поэтому «токен» был фактически всем текстом заявки «Access Token:». Я не особо задумывался об этом в то время, когда отлаживал свой сервис, потому что не понимал, что там не должно быть этого текста.

Как только я исправил эту проблему, сервис начал работать, как ожидалось. .

Итак, в конце концов, я думаю, что все работало так, как ожидалось. На самом деле я не отправлял ожидаемый токен, поэтому я ... не авторизован.

В ответ на запрос строка кода, которую мне пришлось изменить, была такой:

Итак, это Это не на 100% применимо к большинству, потому что я использую бизнес-библиотеку под названием CSLA, но идея та же самая, независимо от того.

После того, как мой вызов b2 c возвращает токен, я сохраняю его в ApplicationContext. User.Identity, который встроен в библиотеку CSLA. Это позволяет мне получить претензию на токен доступа позже. Важным моментом, который следует отнять, является то, что я храню токен в каком-то месте, к которому я могу получить доступ позже, когда захочу добавить его в заголовок авторизации.

Позже, когда я делаю вызов с моим httpclient мне нужно получить этот токен, поэтому изначально я делал это:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue ("Bearer", ((ClaimsIdentity) ApplicationContext.User.Identity) .Claims. FirstOrDefault (c => c .Type == "AccessToken") .ToString () );

Это не правильно. Это отправляло «токен» как со значением «Access Token: [значение токена]. По сути, это было добавление слов «токен доступа» к токену, который мне был необходим для аутентификации, и это не удавалось, потому что слова «токен доступа» фактически не должны быть частью токена, который вы используете для аутентификации.

После того, как я изменил свой вызов на это:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue ("Bearer", ((ClaimsIdentity) ApplicationContext.User.Identity) .Claims.FirstOrDefault (c => 1080 * .Type == "AccessToken") .Value );

Он начал получать только значение токена, и когда он был добавлен в заголовок авторизации, он работал просто отлично.

1 Ответ

0 голосов
/ 20 марта 2020

Редактировать 2 объясняет ответ на мою проблему.

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

...