【问题标题】:NET5.0 Blazor WASM CORS client exceptionNET5.0 Blazor WASM CORS 客户端异常
【发布时间】:2021-02-27 16:13:41
【问题描述】:

我有一个 Blazor WASM 应用程序和一个 Web Api,供 Blzor 通过 HttpClient 调用。两个程序都在同一台机器上运行(也可以在生产环境中运行,这对于小型企业应用程序来说不应该是异国情调的!)。

从 Blazor 客户端调用 Web Api 会导致客户端 CORS 异常

CORS 政策已阻止从源“https://localhost:5001”获取“http://localhost:4040/”的访问权限:没有“Access-Control-Allow-Origin”标头出现在请求的资源。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

这是本案例的预期行为。

在我以前用 PHP 开发的一个具有相同客户端行为的 api 项目中,我可以通过简单地设置响应标头来绕过 CORS 异常,例如

$response = new Response;
$response->setState(false, $route->command);
...
header("Access-Control-Allow-Origin: *");
echo $response;

现在我想在我的 .net 5.0 Web Api 中使用它。我在互联网上找到了不同的文档来处理类似的问题

https://docs.microsoft.com/de-de/aspnet/core/security/cors?view=aspnetcore-5.0 https://www.c-sharpcorner.com/article/enabling-cors-in-asp-net-core-api-application/ https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.cors.infrastructure.corspolicybuilder.withorigins?view=aspnetcore-5.0

并在我的 api 中实现它

    public class Startup {
        //---------------------------------------------------------------------

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        //---------------------------------------------------------------------

        public IConfiguration Configuration { get; }

        //---------------------------------------------------------------------

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices
                    (
                        IServiceCollection services
                    )
                    =>  services
                        .AddCors()
                        .AddSwaggerGen(c => c.SwaggerDoc("v1", new OpenApiInfo { Title = "api", Version = "v1"}) )
                        .AddControllers()
                        ;
        //---------------------------------------------------------------------

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure
                    (
                        IApplicationBuilder app,
                        IWebHostEnvironment env
                    )
                    =>  app.
                        apply( _ =>
                        {
                            if (true) //(env.IsDevelopment())
                            {
                                app
                                .UseDeveloperExceptionPage()
                                .UseSwagger()
                                .UseSwaggerUI( c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "api v1") );
                            }
                        })
                        .UseCors( cors =>
                            cors
                            .AllowAnyHeader()
                            .AllowAnyMethod()
                            .SetIsOriginAllowed( _ => true )
                            .AllowCredentials()
                        )
                        .UseHttpsRedirection()
                        .UseRouting()
                        .UseAuthorization()
                        .UseEndpoints( e => e.MapControllers() )
                        ;
        //---------------------------------------------------------------------
    }

甚至尝试在 ApiController 中设置响应头

    [Route("/")]
    [ApiController]
    public sealed class ServertimeController : ControllerBase
    {
        //[EnableCors("AllowOrigin")]
        [HttpGet]
        public Servertime Get() {

            Response.Headers.Add("Access-Control-Allow-Origin", "*");
            Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT");

            return servertime();
        }
    }

Blazor WASM 客户端看起来像

    private async void onClick()
    {

        var response = await httpClient.GetFromJsonAsync<Servertime> ("http://localhost:4040");
        message = response.servertime;
        this.StateHasChanged();
    }

但它仍然会导致客户端 CORS 异常。 为了绕过这个进行开发,我使用了浏览器扩展“CORS Unblock”,但这不是部署的选项。

避免 Blazor 客户端异常的正确方法是什么, 我错过了什么?

【问题讨论】:

  • 在托管项目模板中,应用程序和 服务 都从同一端口运行,而不仅仅是同一台机器。在您的情况下,您使用的是两个不同的端口,就 CORS 而言,这与使用两台不同的机器没有什么不同。
  • 您真的想将应用程序和 API 托管在不同的端口上吗?在这种情况下,您必须configure CORS on the Web API to allow cross-origin calls。这在文档here 中有解释
  • 处理此问题的正确方法是添加源,而不是禁用端口。这样做很容易,在您的 CORS 配置中使用 policy.WithOrigins("http://localhost:5000", "https://localhost:5001")。至于In an former api project I developed in PHP,,黑客们也读过 SO,现在知道了他们可以针对特定目标尝试的另一个漏洞

标签: c# cors webapi blazor-webassembly


【解决方案1】:

@Dmitriy Grebennikov 的回答也是有效的,但需要进行一些改进以使其更安全。

Startup.csConfigureServices中,在services.AddControllers();之前添加以下代码

services.AddCors(options =>
            {
                options.AddDefaultPolicy(builder => 
                builder.WithOrigins("https://localhost:44338")
                       .AllowAnyMethod()
                       .AllowAnyHeader());
            }); 

确保您的网址不应以 / 结尾。


您可以将多个 url 传递给 WithOrigins 方法。 最后在Startup.csConfigure 方法中在app.UseAuthorization(); 之前和app.UseRouting(); 之后添加以下行

app.UseCors();

代码现在应该可以工作了。

【讨论】:

【解决方案2】:

只需将其添加到 ConfigureServices 方法中:

services.AddCors(options =>
        {
            options.AddPolicy("DevCorsPolicy", builder =>
            {
                builder
                    .AllowAnyOrigin()
                    .AllowAnyMethod()
                    .AllowAnyHeader();
            });
        });

还有这个配置方法:

app.UseCors("DevCorsPolicy");

【讨论】:

  • 禁用 CORS 相当于告诉某人禁用安全性以克服安全性限制。一个非常糟糕的答案。尤其是当正确的方法是使用WithOrigins() 和允许的来源列表时,例如policy.WithOrigins("http://localhost:5000", "https://localhost:5001")
  • @PanagiotisKanavos 仅用于开发目的。这与生产部署无关。这个问题暗示了它。
  • 正确执行此操作只需要多几个字符
  • @PanagiotisKanavos 老实说,我什至不明白为什么默认情况下启用了 cors,在我从事的大多数项目中,它并没有创建安全性......但只有工作和开销。它最初只被浏览器使用,很容易被欺骗,我确实看到了一些程序员实施重大安全漏洞的项目,因为他们相信他们可以依赖它
  • @PatrickBeynio 浏览器需要 CORS。没有它,浏览器出于安全原因拒绝调用 API。 CORS 可防止脚本注入攻击,这种攻击会调用黑客的服务器发送数据或接收更多脚本以执行。 only used by browsers 不仅如此。重点是保护最终用户。 it can be spoofed 如果网站开发人员马虎。 where the programmer implemented major security flaws 那为什么还要系安全带呢?它们可以取下来。
【解决方案3】:
var client = new HttpClient();

var request = new HttpRequestMessage
{
    Method = new HttpMethod("GET"),
    RequestUri = new Uri($"{site.BaseUrl}robots.txt")
};

request.Headers.Add("Accept", "text/plain");
request.SetBrowserRequestMode(BrowserRequestMode.NoCors);

var response = await client.SendAsync(request);

var txt = await response.Content.ReadAsStringAsync();

参考文献

【讨论】:

  • 不行,查询真实发送到服务器,在浏览器中可以看到响应,但是httpresponse会是0状态码,内容为空:(
猜你喜欢
  • 1970-01-01
  • 2021-02-26
  • 2021-04-05
  • 2020-07-27
  • 2020-05-17
  • 1970-01-01
  • 1970-01-01
  • 2020-04-24
  • 2021-02-24
相关资源
最近更新 更多