Asp.Net Core 2.1 Web Api returns 400 从 Angular 6 Web Api 发送请求以获取 access_token

Asp.Net Core 2.1 WebApi returns 400 when sending request from Angular 6 WebApp to get access_token

我有一个应用程序,在服务器端由 asp.net core 2.1 web api 表示,在客户端由 angular 6 表示。服务器端使用 OpenIddict 来支持令牌认证。主要问题是,当请求从 angular 应用程序发送到服务器以生成或刷新客户端 access_token 时,服务器响应 400(错误请求),尽管它是从邮递员一切正常。添加 Cors 策略以允许跨源请求,因为客户端和服务器端位于不同的端口,因此从 angular 到服务器的简单请求可以正常通过。

这是启动 class:

public class Startup
{
    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {
        Configuration = configuration;
        hostingEnvironment = env;
    }

    public IConfiguration Configuration { get; }
    private IHostingEnvironment hostingEnvironment { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContextPool<HospitalContext>(options => 
         {
             options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
             options.UseOpenIddict();
         });

        services.AddCors(options => options.AddPolicy("AllowLocalhost4200", builder => 
        { 
            builder
            .WithOrigins("http://localhost:4200")
            .WithHeaders("Authorization", "Content-type")
            .WithMethods("Get", "Post", "Put", "Delete");
        }));

        services.AddCustomIdentity();
        services.AddCustomOpenIddict(hostingEnvironment);

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

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

        app.UseCors("AllowLocalhost4200");
        app.UseAuthentication();
        app.UseDefaultFiles();
        app.UseStaticFiles();
        app.UseMvc();
        app.InitilizeDb();
    }
}

如果有人需要查看配置,ConfigureServices 方法中的 AddCustomOpenIddict 方法:

 public static IServiceCollection AddCustomOpenIddict(this IServiceCollection services, 
                                                              IHostingEnvironment env)
    {
        services.AddOpenIddict(options =>
        {
            options.AddEntityFrameworkCoreStores<HospitalContext>();
            options.AddMvcBinders();
            options.EnableTokenEndpoint("/connect/token");
            options.EnableAuthorizationEndpoint("/connect/authorize");
            options.AllowRefreshTokenFlow()
                   .AllowImplicitFlow();

            options.SetAccessTokenLifetime(TimeSpan.FromMinutes(30));
            options.SetIdentityTokenLifetime(TimeSpan.FromMinutes(30));
            options.SetRefreshTokenLifetime(TimeSpan.FromMinutes(60));

            if (env.IsDevelopment())
            {
                options.DisableHttpsRequirement();
            }

            options.AddEphemeralSigningKey();
        });

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

        return services;
    }

发送请求的Angular方法是:

public authorize(model: ILoginModel): Observable<Response> {
    return this.http.post(`http://localhost:58300/connect/token`,
                          this.authService.authFormBody(model),
                          {headers: this.authService.authHeaders()});
}

与 this.authService.authFormBody 和 this.authService.authHeaders:

authHeaders(): Headers {
    const headers = new Headers(
    {
        'Content-Type': 'application/x-www-form-urlencoded'
    });
    return headers;
}

authFormBody(model: ILoginModel): string {
    let body = '';
    body += 'grant_type=password&';
    body += 'username=' + model.email + '&';
    body += 'password=' + model.password + '&';
    body += 'scope=OpenId profile OfflineAccess Roles';
    return body;
}

我实际上是基于令牌的身份验证的新手,所以可能在配置或其他方面存在问题。将不胜感激任何解决问题的提议。

首先,尝试允许所有 headers:

https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-2.1#set-the-allowed-request-headers

稍后,准确地说,查看所有 headers 您的 angular 应用正在发送并在您的 cors 策略中允许所有这些。首先,允许 application-x-www-form-urlencoded

您的 authFormBody 方法中似乎有错字:

body += 'grant_type=password$';

这应该写成:

body += 'grant_type=password&';

我发现了一个错误,实际上是我从我的配置中删除了 AddPasswordFlow 并留下了 AllowRefreshTokenFlow() 和 AllowImplicitFlow() 并发送 grant_type=password 到未配置为接受此类的服务器赠款,那是我的错误。应该是:

services.AddOpenIddict(options =>
    {
        //some configs

        options.AllowPasswordFlow()
               .AllowRefreshTokenFlow()
               .AllowImplicitFlow();

        //some configs
    });