ASP.NET Core (React) 应用 – 在 IIS 上的 404.15 错误。

huangapple go评论73阅读模式
英文:

ASP.NET Core (React) app - 404.15 on the IIS

问题

I've found many threads about this issue, but no matter what I change, it just doesn't work. I am desperate as I don't understand what is wrong.

My application works fine if run on IIS Express.

As soon as I deploy it to the IIS, it starts to complain about the "query string is too long."

What I don't understand is why it is calling Account\Login - my application has no controllers or any views. It is ASP.NET Core React template where we don't use controllers but our communication is fully through SignalR. We don't even have API controllers.

I tried to set web.config as is suggested on many places (for example here but it doesn't help.

I have identified that the issue in the code is the setup of authorization in Program.cs/Startup.cs file. However, it is done according to Microsoft's guide.

In my Program.cs, I have this to configure authentication:

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options => options.FallbackPolicy = options.DefaultPolicy);

If I run the application via IIS Express, it loads fine, authenticates the user, and everything seems to be working just fine. As soon as I deploy it to the IIS server, I receive this error:
ASP.NET Core (React) 应用 – 在 IIS 上的 404.15 错误。

Note: I have noticed that even if run on IIS Express, it still sends requests to /Account/Login but it doesn't crash the app for some reason.

What I really don't understand is why it is calling the Account/Login path, it just doesn't exist, and I don't have it set anywhere in the code. And as mentioned, my application has no controllers or views. It's a React application communicating with the server via SignalR (but it doesn't get that far, so SignalR is not involved yet).

If I change the code above to:

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options => options.FallbackPolicy = null);

then it won't crash, but it won't log in the Windows user either.

I've tried many things in the last two days but can't figure out what is wrong.

I appreciate any ideas of what could be wrong.

Edit 1 - web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <security>
      <requestFiltering removeServerHeader="true">
        <requestLimits maxUrl="4096" maxQueryString="5000"></requestLimits>
      </requestFiltering>
    </security>
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
        <add name="X-Frame-Options" value="DENY" />
      </customHeaders>
    </httpProtocol>
    <handlers>
      <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="bin\x86\Debug\net6.0-windows\PPSim.Web.exe" arguments="" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" startupTimeLimit="3600" requestTimeout="23:00:00" hostingModel="inprocess">
      <environmentVariables>
        <environmentVariable name="ASPNETCORE_HTTPS_PORT" value="443" />
        <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
      </environmentVariables>
    </aspNetCore>
  </system.webServer>
  <system.web>
    <httpRuntime enableVersionHeader="false" maxQueryStringLength="32768" maxUrlLength="65536" />
  </system.web>
</configuration>

Edit 2 - Program.cs:

var builder = WebApplication.CreateBuilder(args);

#region Services

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options => options.FallbackPolicy = options.DefaultPolicy);

builder.Services.AddAntiforgery(options =>
{
    options.HeaderName = CsrfConstants.CsrfHeaderName;
    options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
    options.Cookie.SameSite = SameSiteMode.Strict;
});

builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection")));

builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

var settings = new JsonSerializerSettings { ContractResolver = new SignalRContractResolver() };
var serializer = JsonSerializer.Create(settings);
builder.Services.AddSingleton(serializer);

builder.Services.AddHsts(options =>
{
    options.Preload = true;
    options.IncludeSubDomains = true;
    options.MaxAge = TimeSpan.FromDays(60);
});

builder.Services.AddSingleton<IUserSettingsWrapper, UserSettingsWrapper>();
builder.Services.AddSingleton<ISignalREventsPusher, SignalRDataPusher>();

builder.Services.AddSignalR().AddNewtonsoftJsonProtocol(options =>
{
    options.PayloadSerializerSettings.ContractResolver = new CustomCamelCasePropertyNamesContractResolver();
    options.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    options.PayloadSerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
});

builder.Services.AddSingleton<IUserIdProvider, NameUserIdProvider>();
builder.Services.AddLogging(loggingBuilder =>
{
    loggingBuilder.AddConfiguration(builder.Configuration.GetSection("Logging"));
    loggingBuilder.AddConsole();
    loggingBuilder.AddDebug();
});

builder.Services.AddCors(options =>
{
    options.AddPolicy("CORSPermission", policy =>
    {
        policy.AllowAnyHeader()
            .AllowAnyMethod()
            .SetIsOriginAllowed(host => true)
            .AllowCredentials();
    });
});

#endregion

var app = builder.Build();

#region Configure

var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

    if (string.Equals(requestPath, "/", StringComparison.OrdinalIgnoreCase)
        || string.Equals(requestPath, "/index.html", StringComparison.OrdinalIgnoreCase))
    {
        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append(CsrfConstants.CsrfCookiesName, tokenSet.RequestToken!,
            new CookieOptions
            {
                HttpOnly = false,
                Secure = true,
                SameSite = SameSiteMode.Strict
            });
    }

    return next(context);
});

if (!app.Environment.IsDevelopment())
{
}
else
{
    app.UseHsts();
    //app.UseExceptionHandler("/Home/Error");
}

app.UseStaticFiles();

app.UseHttpsRedirection();
app.UseRouting();
app.UseCors("CORSPermission")

app.UseAuthentication();
app.UseAuthorization();
app.UseFileServer();

#endregion

app.MapFallbackToFile("index.html");

app.UseEndpoints(endpoints =>
{
    endpoints.MapHub<SimulatorHub>("/SimulatorHub",
        options => options.Transports = GetTransportToUse(app.Environment)).RequireCors("CORSPermission");
});

app.Run();
英文:

I've found many threads about this issue, but not matter what I change it just doesn't work. I am desperate as I don't understand what is wrong.

My application works fine if run on IIS Express.

As soon as I deploy it to the IIS, it starts to complain about the "query string is too long"

What I don't understand is why it is calling Account\Login - my application has no controllers or any views. It is ASP.NET Core React template where we don't use controllers but our communication is fully through SignalR. We don't have even API controllers.

I tried to set web.config as is suggested on many places (for example here but it's suggested in many other threads) - it doesn't help.

I have identified that the issue in the code is setup of authorization in Program.cs/Startup .cs file. However, it is done according to Microsoft guide.

In my Program.cs I have this to configure authentication:

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options =&gt; options.FallbackPolicy = options.DefaultPolicy);

If I run application via the IIS Express, it loads fine, authenticates user and everything seems to be working just fine. As soon as I deploy it to the IIS server, I receive this error:
ASP.NET Core (React) 应用 – 在 IIS 上的 404.15 错误。

Note: I have noticed that even if run on IIS Express, it still sends requests to /Account/Login but it doesn't crash the app for some reason.

What I really don't understand is, why is it calling Account/Login path, it just doesn't exist and I don't have it set anywhere in the code. And as mentioned, my application have no controllers or views. It's react application communicating with server via SignalR (but it doesn't get that far, so SignalR is not involved yet).

If I change the code above to:

builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options =&gt; options.FallbackPolicy = null);

then it won't crash, but it won't log in windows user either.

I tried many things in last two days but can't figure out, what is wrong.

I appreciate any ideas of what could be wrong.

Edit 1 - web.config:

&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;configuration&gt;
&lt;system.webServer&gt;
&lt;security&gt;
&lt;requestFiltering removeServerHeader=&quot;true&quot;&gt;
&lt;requestLimits maxUrl=&quot;4096&quot; maxQueryString=&quot;5000&quot;&gt;&lt;/requestLimits&gt;
&lt;/requestFiltering&gt;
&lt;/security&gt;
&lt;httpProtocol&gt;
&lt;customHeaders&gt;
&lt;remove name=&quot;X-Powered-By&quot; /&gt;
&lt;add name=&quot;X-Frame-Options&quot; value=&quot;DENY&quot; /&gt;
&lt;/customHeaders&gt;
&lt;/httpProtocol&gt;
&lt;handlers&gt;
&lt;add name=&quot;aspNetCore&quot; path=&quot;*&quot; verb=&quot;*&quot; modules=&quot;AspNetCoreModuleV2&quot; resourceType=&quot;Unspecified&quot; /&gt;
&lt;/handlers&gt;
&lt;aspNetCore processPath=&quot;bin\x86\Debug\net6.0-windows\PPSim.Web.exe&quot; arguments=&quot;&quot; stdoutLogEnabled=&quot;true&quot; stdoutLogFile=&quot;.\logs\stdout&quot; startupTimeLimit=&quot;3600&quot; requestTimeout=&quot;23:00:00&quot; hostingModel=&quot;inprocess&quot;&gt;
&lt;environmentVariables&gt;
&lt;environmentVariable name=&quot;ASPNETCORE_HTTPS_PORT&quot; value=&quot;443&quot; /&gt;
&lt;environmentVariable name=&quot;ASPNETCORE_ENVIRONMENT&quot; value=&quot;Development&quot; /&gt;
&lt;/environmentVariables&gt;
&lt;/aspNetCore&gt;
&lt;/system.webServer&gt;
&lt;system.web&gt;
&lt;httpRuntime enableVersionHeader=&quot;false&quot; maxQueryStringLength=&quot;32768&quot; maxUrlLength=&quot;65536&quot; /&gt;
&lt;/system.web&gt;
&lt;/configuration&gt;

Edit 2 - Program.cs:

var builder = WebApplication.CreateBuilder(args);
#region Services
builder.Services.AddAuthentication(NegotiateDefaults.AuthenticationScheme).AddNegotiate();
builder.Services.AddAuthorization(options =&gt; options.FallbackPolicy = options.DefaultPolicy);
builder.Services.AddAntiforgery(options =&gt;
{
options.HeaderName = CsrfConstants.CsrfHeaderName;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
});
builder.Services.AddDbContext&lt;ApplicationDbContext&gt;(options =&gt;
options.UseSqlite(builder.Configuration.GetConnectionString(&quot;DefaultConnection&quot;)));
builder.Services.AddIdentity&lt;ApplicationUser, IdentityRole&gt;()
.AddEntityFrameworkStores&lt;ApplicationDbContext&gt;()
.AddDefaultTokenProviders();
var settings = new JsonSerializerSettings { ContractResolver = new SignalRContractResolver() };
var serializer = JsonSerializer.Create(settings);
builder.Services.AddSingleton(serializer);
builder.Services.AddHsts(options =&gt;
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(60);
});
builder.Services.AddSingleton&lt;IUserSettingsWrapper, UserSettingsWrapper&gt;();
builder.Services.AddSingleton&lt;ISignalREventsPusher, SignalRDataPusher&gt;();
builder.Services.AddSignalR().AddNewtonsoftJsonProtocol(options =&gt;
{
options.PayloadSerializerSettings.ContractResolver = new CustomCamelCasePropertyNamesContractResolver();
options.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.PayloadSerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
});
builder.Services.AddSingleton&lt;IUserIdProvider, NameUserIdProvider&gt;();
builder.Services.AddLogging(loggingBuilder =&gt;
{            loggingBuilder.AddConfiguration(builder.Configuration.GetSection(&quot;Logging&quot;));
loggingBuilder.AddConsole();
loggingBuilder.AddDebug();
});
builder.Services.AddCors(options =&gt;
{
options.AddPolicy(&quot;CORSPermission&quot;, policy =&gt;
{
policy.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed(host =&gt; true)
.AllowCredentials();
});
});
#endregion
var app = builder.Build();
#region Configure
var antiforgery = app.Services.GetRequiredService&lt;IAntiforgery&gt;();
app.Use((context, next) =&gt;
{
var requestPath = context.Request.Path.Value;
if (string.Equals(requestPath, &quot;/&quot;, StringComparison.OrdinalIgnoreCase)
|| string.Equals(requestPath, &quot;/index.html&quot;, StringComparison.OrdinalIgnoreCase))
{
var tokenSet = antiforgery.GetAndStoreTokens(context);
context.Response.Cookies.Append(CsrfConstants.CsrfCookiesName, tokenSet.RequestToken!,
new CookieOptions
{
HttpOnly = false,
Secure = true, // 15018: Cookie generated by application does not contain the “Secure flag” attribute
SameSite = SameSiteMode.Strict
});
}
return next(context);
});
if (!app.Environment.IsDevelopment())
{
}
else
{
app.UseHsts();
//app.UseExceptionHandler(&quot;/Home/Error&quot;);
}
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(&quot;CORSPermission&quot;)
app.UseAuthentication();
app.UseAuthorization();
app.UseFileServer();
#endregion
app.MapFallbackToFile(&quot;index.html&quot;);
app.UseEndpoints(endpoints =&gt;
{
endpoints.MapHub&lt;SimulatorHub&gt;(&quot;/SimulatorHub&quot;,
options =&gt; options.Transports = GetTransportToUse(app.Environment)).RequireCors(&quot;CORSPermission&quot;);
});
app.Run();

答案1

得分: 1

以下是翻译好的部分:

"在您的问题的评论部分,关于我们洞察的后续。

的确,存在一个无限重定向到account/login URL。

由于您没有这样的控制器或页面,该页面是由ASP.NET Core Identity提供的开箱即用。

来自该页面。

ASP.NET Core Identity为ASP.NET Core Web应用程序添加了用户界面(UI)登录功能。

生成的项目将ASP.NET Core Identity作为Razor类库提供。
Identity Razor类库公开了Identity区域的端点。例如:

  • /Identity/Account/Login

这是由您在program.cs中调用的以下调用激活的。

builder.Services.AddIdentity&lt;ApplicationUser, IdentityRole&gt;()
.AddEntityFrameworkStores&lt;ApplicationDbContext&gt;()
.AddDefaultTokenProviders();

为解决此问题,应删除该行,因为您将使用Windows身份验证。"

英文:

As a follow-up on our insights from the comments section in your question.

There's indeed an infinite redirect going on to the account/login url.

Since you don't have such a controller and/or page, that one is provided out-of-the-box by ASP.NET Core Identity.

From that page.
> ASP.NET Core Identity adds user interface (UI) login functionality to ASP.NET Core web apps.

> The generated project provides ASP.NET Core Identity as a Razor Class Library.
> The Identity Razor Class Library exposes endpoints with the Identity area. For example:
> - /Identity/Account/Login

That does get activated by below call you have in program.cs.

builder.Services.AddIdentity&lt;ApplicationUser, IdentityRole&gt;()
.AddEntityFrameworkStores&lt;ApplicationDbContext&gt;()
.AddDefaultTokenProviders();

To resolve the issue, that line is to be removed since you'll be using Windows authentication.

huangapple
  • 本文由 发表于 2023年3月3日 23:28:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/75628993.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定