【问题标题】:Asp.Net Core 2.1 WebApi returns 400 when sending request from Angular 6 WebApp to get access_token当从 Angular 6 WebApp 发送请求以获取 access_token 时,Asp.Net Core 2.1 WebApi 返回 400
【发布时间】:2018-11-29 20:54:21
【问题描述】:

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

这里是启动类:

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

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

【问题讨论】:

    标签: asp.net-web-api angular6 openiddict


    【解决方案1】:

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

    services.AddOpenIddict(options =>
        {
            //some configs
    
            options.AllowPasswordFlow()
                   .AllowRefreshTokenFlow()
                   .AllowImplicitFlow();
    
            //some configs
        });
    

    【讨论】:

      【解决方案2】:

      首先,尝试允许所有标题:

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

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

      【讨论】:

      • 首先,我尝试允许所有标题,但这并没有改变任何东西。其次,在这种情况下,角度发送带有“Content-Type”标头的请求,仅此而已......并且在 Cors Policy 中是允许的,并且关于“application-x-www-form-urlencoded”,它是主体的类型在内容类型标头中指定的请求,而不是我理解的标头。所以,不幸的是,这不起作用。
      • 您的 Angular 应用在​​ http://localhost:4200 上运行?不是 https,不是其他端口?
      • 看起来很平常。我唯一看到的是:尝试使用大写的动词或allowallmethod()
      【解决方案3】:

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

      body += 'grant_type=password$';
      

      这应该写成:

      body += 'grant_type=password&';
      

      【讨论】:

      • 抱歉打错了,只是粘贴的时候打错了……即使是这样,至少会到达服务器'/connect/token'上的方法并发送我自己定义的带有描述的错误请求。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-03
      • 2020-12-11
      • 2019-03-25
      • 2018-06-12
      • 1970-01-01
      相关资源
      最近更新 更多