从浏览器获取 401,但从邮递员获取 200,使用 Asp.net 核心和 Identityserver 4

时间:2021-01-24 15:58:27

标签: asp.net-core authorization postman identityserver4

我尝试了所有方法,但当我尝试从 React App 访问我的 api 时,我不断收到 401 错误。 我的 Api 是一个受身份服务器保护的 asp.net 核心。

从邮递员那里,我可以请求访问令牌并调用 api,它工作正常。 从浏览器中,我可以获得有效的访问令牌,但任何 api 调用都失败并显示 401。

在浏览器中失败的确切请求,在邮递员上工作正常(从开发工具复制为 cUrl,然后在邮递员中导入)。

我已经尝试了 http 和 https,我已经检查了启动时元素的顺序,我已经配置了 CORS……什么都没有。

我使用相同的 Web 应用作为 Identity Server 和 Api 服务器。

这是我的启动文件:

using FluentValidation.AspNetCore;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Pesabooks.Api.Common;
using Pesabooks.Application;
using Pesabooks.Application.Common.Interfaces;
using Pesabooks.Domain.Session;
using Pesabooks.Infrastructure;
using System.Threading.Tasks;

namespace Pesabooks.Api
{
    public class Startup
    {
        public Startup(IConfiguration configuration, IWebHostEnvironment environment)
        {
            Configuration = configuration;
            Environment = environment;
        }

        public IConfiguration Configuration { get; }
        public IWebHostEnvironment Environment { get; }
        readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {

            services.AddCors(options =>
            {
                options.AddPolicy(name: MyAllowSpecificOrigins,
                    builder =>
                    {
                        builder.WithOrigins("http://localhost:3000").AllowAnyMethod().AllowAnyHeader();
                    });
            });



            services.AddControllersWithViews()
                 .AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<IPesabooksDbContext>()); ;

            services.AddApplication();
            services.AddInfrastructure(Configuration, Environment);

            services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie("Cookies", options =>
            {
                options.Cookie.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Lax;
            });

            services.AddAuthentication("Bearer")
                  .AddJwtBearer("Bearer", options =>
                  {
                      options.Authority = "http://localhost:5000";

                      options.TokenValidationParameters = new TokenValidationParameters
                      {
                          ValidateAudience = false,
                      };

                      //options.Audience = "pesabooks";
                      options.RequireHttpsMetadata = false;
                  });

            services.ConfigureApplicationCookie(options =>
            {
                options.Events.OnRedirectToLogin = context =>
                {
                    context.Response.Headers["Location"] = context.RedirectUri;
                    context.Response.StatusCode = 401;
                    return Task.CompletedTask;
                };

            });
   

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Pesabooks.Api", Version = "v1" });
                c.OperationFilter<AddRequiredHeaderParameter>();
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseCookiePolicy(new CookiePolicyOptions { MinimumSameSitePolicy = Microsoft.AspNetCore.Http.SameSiteMode.Strict });

            if (env.IsDevelopment())
            {

                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Pesabooks.Api v1"));
            }

            app.UseCustomExceptionHandler();
            // app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseRouting();
            app.UseCors(MyAllowSpecificOrigins);

            app.UseAuthentication();
            app.UseAuthorization();
            app.UseIdentityServer();
            app.UseTenantMiddleware();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "areas",
                    pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}"
                 );
                endpoints.MapControllers();
            });
        }
    }
}

这是我的身份服务器客户端设置:

{
  "IdentityServer": {
    "Clients": [
      {
        "ClientId": "Pesabooks.WebApp",
        "ClientName": "Pesabooks Web App",
        "AllowedGrantTypes": [ "implicit" ],
        "AllowedScopes": [ "openid", "profile", "api" ],
        "RequireClientSecret": false,
        "RedirectUris": [ "http://localhost:3000/signin-oidc" ],
        "PostLogoutRedirectUris": [ "http://localhost:3000/signout-oidc" ],
        "AllowedCorsOrigins": [ "http://localhost:3000" ],
        "AllowAccessTokensViaBrowser": true,
        "Enabled": true
      },
      {
        "ClientName": "Pesabooks.IntegrationTests",
        "ClientId": "Pesabooks.IntegrationTests",
        "AllowedGrantTypes": [ "password" ],
        "AllowedScopes": [ "openid", "profile" ],
        "ClientSecrets": [ { "Value": "*****" } ],
        "Enabled": true
      },
      {
        "ClientName": "Postman",
        "ClientId": "postman",
        "RequirePkce": false,
        "AllowedGrantTypes": [ "authorization_code" ],
        "AllowOfflineAccess": true,
        "IdentityTokenLifetime": 86400,
        "AccessTokenLifetime": 86400,
        "RedirectUris": [ "https://www.getpostman.com/oauth2/callback" ],
        "PostLogoutRedirectUris": [ "https://www.getpostman.com" ],
        "AllowedCorsOrigins": [ "https://www.getpostman.com" ],
        "AllowedScopes": [ "openid", "profile", "email", "api" ],
        "ClientSecrets": [ { "Value": "*****" } ],
        "AllowAccessTokensViaBrowser": true,
        "RequireConsent": false,
        "EnableLocalLogin": true,
        "Enabled": true
      }
    ]
  }
}

这是在浏览器中失败但在邮递员中有效的请求示例:

 curl 'http://localhost:5000/Account/Login?ReturnUrl=%2Fapi%2FAccounts%3FOnlySavings%3Dfalse%26IncludeDeactivated%3Dfalse' \
      -H 'Connection: keep-alive' \
      -H 'Accept: application/json' \
      -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjdBQjI4QUQzNEQ3OUMwOTNCMkY2NjZEQUU5MTYwQzczIiwidHlwIjoiYXQrand0In0.eyJuYmYiOjE2MTE1MDA4NDgsImV4cCI6MTYxMTUwNDQ0OCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwL3Jlc291cmNlcyIsImNsaWVudF9pZCI6IlBlc2Fib29rcy5XZWJBcHAiLCJzdWIiOiIxIiwiYXV0aF90aW1lIjoxNjExNTAwODE4LCJpZHAiOiJsb2NhbCIsImp0aSI6IkYzRkE5MUIxRUM0MzIyNkRBNEZCNDU1QjQ2MTE1MzI5Iiwic2lkIjoiQTE3RDVDQjY3QTIxMDc0MjE4QzgyNTE1RjI5QjdGQUYiLCJpYXQiOjE2MTE1MDA4NDgsInNjb3BlIjpbIm9wZW5pZCIsInByb2ZpbGUiLCJhcGkiXSwiYW1yIjpbInB3ZCJdfQ.gGmUUmZNZLjhyY47diPXQHGXO0k1B8mss8FIdQuecFmp-SxRFls6nF7fU3bqQdQcadpIrZEjDGG2wth8IZIqg82K5L4jr9Nt8Rp8JMdvC-zn7TbHKV670QSYF6NIq5AKWNMi86oNfk9QYEIjM7p5DWjzSjH5LAmINQjwCNG0QhXccSqbUkmVxxsYQkCOfZnlsshrswP41ocNs1s_363v070Tc6ayrxBSYiqM5AbLs_5y4iSXgP1TzWdwxcavBng-vEA0lp5hU0ZNggmBid_GOrgKRfHNzv8518RfHtpa1VwptdkRMiba18t-HNezMw7WMh432Q6RxRvJGW6iq7S8eg' \
      -H 'psbk-tenant: 5' \
      -H 'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36' \
      -H 'Sec-GPC: 1' \
      -H 'Origin: http://localhost:3000' \
      -H 'Sec-Fetch-Site: same-site' \
      -H 'Sec-Fetch-Mode: cors' `
      -H 'Sec-Fetch-Dest: empty' \
      -H 'Referer: http://localhost:3000/' \
      -H 'Accept-Language: en-US,en;q=0.9' \
      --compressed

这是我在日志中得到的:

[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was not authenticated.

[11:28:48 Debug] IdentityServer4.Hosting.CorsPolicyProvider
CORS request made for path: /.well-known/openid-configuration from origin: http://localhost:3000

[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was not authenticated.

[11:28:48 Debug] IdentityServer4.Services.InMemoryCorsPolicyService
Client list checked and origin: http://localhost:3000 is allowed

[11:28:48 Information] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was challenged.

[11:28:48 Debug] IdentityServer4.Hosting.CorsPolicyProvider
CorsPolicyService allowed origin: http://localhost:3000

[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was not authenticated.

[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was not authenticated.

[11:28:48 Debug] IdentityServer4.Hosting.EndpointRouter
Request path /.well-known/openid-configuration matched to endpoint type Discovery

[11:28:48 Debug] IdentityServer4.Hosting.EndpointRouter
Endpoint enabled: Discovery, successfully created handler: IdentityServer4.Endpoints.DiscoveryEndpoint

[11:28:48 Information] IdentityServer4.Hosting.IdentityServerMiddleware
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.DiscoveryEndpoint for /.well-known/openid-configuration

[11:28:48 Debug] IdentityServer4.Endpoints.DiscoveryEndpoint
Start discovery request

[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was successfully authenticated.

[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was successfully authenticated.

[11:28:48 Debug] Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler
AuthenticationScheme: Identity.Application was successfully authenticated.

[11:28:48 Debug] IdentityServer4.Hosting.EndpointRouter
Request path /connect/checksession matched to endpoint type Checksession

[11:28:48 Debug] IdentityServer4.Hosting.EndpointRouter
Endpoint enabled: Checksession, successfully created handler: IdentityServer4.Endpoints.CheckSessionEndpoint

[11:28:48 Information] IdentityServer4.Hosting.IdentityServerMiddleware
Invoking IdentityServer endpoint: IdentityServer4.Endpoints.CheckSessionEndpoint for /connect/checksession

[11:28:48 Debug] IdentityServer4.Endpoints.CheckSessionEndpoint
Rendering check session result

提前致谢。

2 个答案:

答案 0 :(得分:0)

为了帮助您调试,您应该配置您的日志并显示它们的调试输出。在 IdentityServer 解决方案中,您通常在 program.cs 类中控制它,如下面的示例来自 here

只需将日志级别设置为 Debug 即可查看更多操作见解。

  Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Debug()
            .MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
            .MinimumLevel.Override("Microsoft.Hosting.Lifetime", LogEventLevel.Information)
            .MinimumLevel.Override("System", LogEventLevel.Warning)
            .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information)
            .Enrich.FromLogContext()
            // uncomment to write to Azure diagnostics stream
            //.WriteTo.File(
            //    @"D:\home\LogFiles\Application\identityserver.txt",
            //    fileSizeLimitBytes: 1_000_000,
            //    rollOnFileSizeLimit: true,
            //    shared: true,
            //    flushToDiskInterval: TimeSpan.FromSeconds(1))
            .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Code)
            .CreateLogger();

答案 1 :(得分:0)

我做了一个测试并创建了一个单独的 web api 项目,它立即生效。

为身份服务器和我的 api 使用相同的服务器是一个坏主意,并且由于某些原因不起作用。

解决方案:为身份服务器使用专用的 Web 应用