繁体   English   中英

401 在 Xamarin.Forms 上未经 Azure b2c 授权

[英]401 Unauthorized with Azure b2c on Xamarin.Forms

我有一个 Xamarin.Forms 应用程序,用于连接到应用服务后端,我正在尝试使用 Auzre B2C JWT 令牌进行身份验证。

通过各种教程,我设法使用微软帐户进行 B2C 设置,并且我能够创建用户、更改密码和生成访问令牌。

我的下一步是将 [Authorize] 属性添加到我的控制器并尝试将该令牌传递给我的应用程序服务并授权用户,但无论我尝试什么,我的服务都会收到 401 Unauthorized 响应。

  • 我正在将 JWT 令牌添加到我的 HttpClient 的 Authorization 标头中,并且它正在访问服务。
  • 我可以将我的令牌粘贴到https://jwt.ms/ 中,它会正确地告诉我令牌中的内容。
  • 我已经实现了这段代码,试图找出问题所在。

startup.cs 中的 ConfigureServices 如下所示:

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();
        }

配置看起来像这样:

        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 错误,这是在它击中 Startup.cs 中连接的 OnChallenge 事件之后。 根据上面的链接,这就是在向用户返回 401 之前调用的内容,因此服务似乎正在接收正确的令牌并进行身份验证,但也许我没有设置正确的权限?

我不确定从哪里开始,但任何指导将不胜感激。

编辑:

正如下面的评论中提到的,我能够使用通过我的应用程序登录后生成的访问令牌来卷曲我的网站,如下所示:

curl https://mywebsite.azurewebsites.net/api/Values -i --header "Authorization: Bearer [TOKEN]"

这似乎没有问题,所以这似乎与我如何通过我的应用程序调用控制器有关,而不是身份验证本身。

编辑2(解决方案):

因此,根据 Edit 1,我是正确的,因为这正是我将令牌添加到授权标头的方式。 这不是我最辉煌的时刻,但我并没有针对包含我的访问令牌的声明调用 .Value。 我只是在声明本身上调用 .ToString(),所以“令牌”实际上是整个声明文本“访问令牌:”。 在调试我的服务时,我并没有想太多,因为我没有意识到它不应该有那个文本。

一旦我纠正了这个问题,服务就开始按预期工作。

所以,最后,我想这一切都按预期进行。 事实上,我没有发送预期的令牌,所以我......未经授权。

根据要求,我必须更改的代码行是这样的:

因此,这不会 100% 适用于大多数人,因为我使用的是一个名为 CSLA 的业务库,但无论如何这个想法都是一样的。

在我的 b2c 调用返回令牌后,我将它存储在 CSLA 库中内置的 ApplicationContext.User.Identity 中。 这允许我稍后获得访问令牌声明。 重要的部分是我将令牌存储在某个地方,以便稍后我想将其添加到授权标头时可以访问它。

后来,当我使用 httpclient 进行调用时,我需要获取该令牌,因此最初我是这样做的:

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

这不正确。 这是发送“令牌”作为值“访问令牌:[令牌值]。本质上,它是将“访问令牌”字样添加到我需要进行身份验证的令牌中,但失败了,因为“访问令牌”字样实际上不应该是您用于身份验证的令牌的一部分。

在我改变我的电话之后:

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

它开始只获取令牌值,当它被添加到授权标头时,它工作得很好。

编辑 2 解释了我的问题的答案。

我没有将令牌正确添加到授权标头中,因此该服务无法对令牌进行身份验证,或者更确切地说,它认为令牌无效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM