为什么具有相同防伪验证功能的同一个ASP.NET Core应用程序在一台计算机上而不是另一台计算机上工作?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了为什么具有相同防伪验证功能的同一个ASP.NET Core应用程序在一台计算机上而不是另一台计算机上工作?相关的知识,希望对你有一定的参考价值。
基本上,我下面有ASP.NET Core MVC应用程序:
Program.cs
public class Program
{
public static void Main(string[] args) =>
CreateWebHostBuilder(args)
.Build()
.Run();
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(ConfigureAppConfiguration)
.UseSerilog(ConfigureSerilog)
.UseKestrel(options => options.AddServerHeader = false)
.UseIISIntegration()
.CaptureStartupErrors(true)
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>();
public static void ConfigureAppConfiguration(WebHostBuilderContext context, IConfigurationBuilder builder)
{
builder.SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
var envFileName = $"appsettings.{context.HostingEnvironment.EnvironmentName}.json";
builder.AddJsonFile(envFileName, optional: false, reloadOnChange: true);
builder.AddEnvironmentVariables();
}
public static void ConfigureSerilog(WebHostBuilderContext context, LoggerConfiguration builder)
{
var elasticSection = context.Configuration.GetSection("serilog:elastic");
var elasticOptions = new ElasticsearchSinkOptions(new Uri(elasticSection.GetValue<string>("nodeUris")));
elasticSection.Bind(elasticOptions);
builder
.Enrich.WithProperty("EnvironmentName", context.HostingEnvironment.EnvironmentName)
.Enrich.FromLogContext()
.Filter.ByExcluding(Matching.WithProperty<string>("RequestPath", p => p.StartsWith("/health")))
.WriteTo.Elasticsearch(elasticOptions)
.WriteTo.Console();
}
}
Startup.cs
public class Startup
{
private readonly ILogger<Startup> _logger;
private readonly IWebHostEnvironment _hostingEnvironment;
public static bool IsDev;
public Startup(ILogger<Startup> logger, IConfiguration configuration, IWebHostEnvironment hostingEnvironment)
{
_logger = logger;
_hostingEnvironment = hostingEnvironment;
Configuration = configuration;
ConfigurationManager.Instance = new ConfigurationManager(Configuration);
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
if (!_hostingEnvironment.IsProduction())
{
services.AddRequestResponseMiddleware();
}
_logger.LogInformation("Startup: Configure Services");
services.AddDbContext<MyAppDataContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("MyAppConnectionString")));
services.AddAntiforgery();
services
.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
options.SignIn.RequireConfirmedEmail = true;
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.User.RequireUniqueEmail = true;
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@-._0123456789";
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Tokens.ProviderMap.Add("Default",
new TokenProviderDescriptor(typeof(IUserTwoFactorTokenProvider<ApplicationUser>)));
})
.AddEntityFrameworkStores<MyAppDataContext>()
.AddDefaultTokenProviders();
services.Configure<DataProtectionTokenProviderOptions>(options =>
{
options.Name = "Default";
var tokenDurationActivationLinkString = ConfigurationManager.Instance["TokenDurationInHoursOfActivationAccountLink"];
var tokenDurationActivationLink = double.Parse(tokenDurationActivationLinkString);
options.TokenLifespan = TimeSpan.FromHours(tokenDurationActivationLink);
});
services.AddDataProtection().PersistKeysToFileSystem(new DirectoryInfo(Path.GetTempPath()));
services.AddSession(options =>
{
// Set a short timeout for easy testing.
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
});
services.AddLocalization(options => options.ResourcesPath = "App_LocalResources");
services
.AddMvc(options => options.EnableEndpointRouting = false)
.AddRazorPagesOptions(options =>
{
options.Conventions.AuthorizeFolder("/Account/Manage");
options.Conventions.AuthorizePage("/Account/Logout");
})
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
var corsOrigin = Configuration.GetSection("corsOrigins:combo").Get<string[]>();
services.AddCors(options => options
.AddPolicy("AllowCombo", builder => builder
.WithOrigins(corsOrigin)
.AllowAnyHeader()));
services.AddEFSecondLevelCache();
services.AddSingleton(typeof(ICacheManager<>), typeof(BaseCacheManager<>));
services.AddSingleton(typeof(ICacheManagerConfiguration),
new CacheManager.Core.ConfigurationBuilder()
.WithJsonSerializer()
.WithMicrosoftMemoryCacheHandle(instanceName: "MemoryCache1")
.WithExpiration(ExpirationMode.Absolute, TimeSpan.FromMinutes(10))
.Build());
services.AddHealthChecks();
services.AddMemoryCache();
services.AddHangfire(configuration => configuration.UseMemoryStorage());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
_logger.LogInformation("Startup: Configure HTTP Request Pipeline");
IsDev = env.IsDevelopment();
app.UseCookiePolicy(new CookiePolicyOptions
{
HttpOnly = HttpOnlyPolicy.Always,
Secure = CookieSecurePolicy.Always
});
if (IsDev)
{
app.UseDeveloperExceptionPage(new DeveloperExceptionPageOptions());
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseHsts();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseSession();
var supportedCultures = new[]
{
new CultureInfo("en"),
new CultureInfo("fr"),
};
var requestLocalizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
};
app.UseRequestLocalization(requestLocalizationOptions);
requestLocalizationOptions.RequestCultureProviders.Insert(0, new UrlRequestCultureProvider());
if (!_hostingEnvironment.IsProduction())
{
app.UseRequestResponseMiddleware();
}
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode == 404)
{
context.Response.Redirect("/Account/Login");
}
});
app.Use(async (context, next) =>
{
context.Response.Headers.Remove("x-powered-by");
context.Response.Headers.Remove("server");
context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("X-XSS-Protection", "1; mode=block");
await next();
});
app.UseMvc(route =>
{
route.MapRoute(
name: "Areas",
template: "{area:exists}/{controller=Documents}/{action=Index}/{id?}"
);
route.MapRoute(
name: "default",
template: "{controller=Account}/{action=Login}/{id?}");
});
app.UseCors("AllowCombo");
app.UseHealthChecks("/health");
app.UseHangfireServer();
app.UseHangfireDashboard();
var logger = app.ApplicationServices.GetService<ILogger<Result>>();
var job = new UpdateHiPayCompanyIdentificationJob(logger);
BackgroundJob.Enqueue(() => job.UpdateCompaniesIdentificationAsync());
}
}
AccountController.cs
:
[Authorize]
public class AccountController : BaseController
{
public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager,
ILogger<AccountController> logger, MyAppDataContext dataContext)
: base(userManager, signInManager, logger, dataContext)
{
}
// GET: /Account/Login
[AllowAnonymous]
public async Task<ActionResult> Login(string returnUrl = null)
{
if (User.Identity.IsAuthenticated)
{
var user = await UserManager.FindByNameAsync(User.Identity.Name);
return await UserManager.IsInRoleAsync(user, "Admin") ||
await UserManager.IsInRoleAsync(user, "Sales")
? RedirectToAction("Index", "Companies", new {Area = "Sales"})
: RedirectToAction("Index", "Documents", new {Area = "Company", id = user.CompanyId});
}
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
return View();
}
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
var result = await SignInManager.PasswordSignInAsync(
model.Email,
model.Password,
model.RememberMe,
true);
if (result.Succeeded)
{
var user = await UserManager.FindByEmailAsync(model.Email);
return await UserManager.IsInRoleAsync(user, "Admin") ||
await UserManager.IsInRoleAsync(user, "Sales")
? RedirectToAction("Index", "Companies", new {Area = "Sales"})
: RedirectToAction("Index", "Documents", new {Area = "Company", id = user.CompanyId});
}
if (result.IsLockedOut)
{
return View("Lockout");
}
if (!result.IsNotAllowed)
{
ModelState.AddModelError(string.Empty, Resource.InvalidLoginAttempt);
}
return View(model);
}
// GET: /Account/ConfirmEmail
[AllowAnonymous]
public async Task<ActionResult> ConfirmEmail(string code, string userId)
{
if (code == null || userId == null)
{
return View("Error");
}
await SignInManager.SignOutAsync();
var user = await UserManager.FindByIdAsync(userId);
if (user == null)
{
Logger.LogDebug("User not found");
return View("TokenError");
}
if (user.EmailConfirmed)
{
return RedirectToAction("Login");
}
var result = await UserManager.ConfirmEmailAsync(user, code);
if (result.Succeeded)
{
await SignInManager.SignInAsync(await UserManager.FindByIdAsync(userId), true);
return RedirectToAction("CreatePasswordView");
}
return result.Errors.Any() &&
result.Errors.Any(identityError => identityError.Code == "InvalidToken")
? View("TokenError")
: View(result.Succeeded
? "ConfirmEmail"
: "Error");
}
}
Login.cshtml
:
@using MyApp.Core.App_LocalResources
@using Microsoft.AspNetCore.Mvc.Rendering
@model MyApp.Core.Models.Account.LoginViewModel
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@{
ViewBag.Title = MyApp.Core.App_LocalResources.Views.Account.Login.Account_Login_Title;
}
@using (Html.BeginForm("Login", "Account", new { ViewBag.ReturnUrl }, FormMethod.Post, true, new { role = "form", @class = "form-horizontal contentPane2" }))
{
@Html.AntiForgeryToken()
<div class="tab" style="width: 100%">
<div id="TopHeader" class="documentTabHeaderTop"> </div>
<div class="container-fluid documentTitleHeader text-center documentTabHeaderTd-active">
<div class="col-xs-12 col-sm-12 col-lg-12 headImage">@Html.ValidationSummary(true)</div>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 col-lg-offset-1 col-md-offset-1 col-xs-offset-1 col-sm-offset-0 buttons-visible">
<div>
<input type="submit" id="ContinueButton" value="@Resource.Continue.ToUpper()" class="buttonItem buttonItem-valid" />
</div>
</div>
</div>
<div class="form-group">
</div>
<div class="form-group has-feedback">
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 col-lg-offset-1 col-md-offset-1 col-sm-offset-1 col-xs-offset-1">
@Html.TextBoxFor(m => m.Email, new { @class = "form-control", @placeholder = Resource.Login, aria_describedby = "EMailStatus" })
<span class="glyphicon form-control-feedback" aria-hidden="true" id="Email1"></span>
</div>
@Html.ValidationMessageFor(m => m.Email, null, new { @class = "sr-only", id = "EMailStatus" })
</div>
<div class="form-group has-feedback">
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 col-lg-offset-1 col-md-offset-1 col-sm-offset-1 col-xs-offset-1">
@Html.PasswordFor(m => m.Password, new { @class = "form-control", @placeholder = Resource.Password, aria_describedby = "PasswordBlock" })
<span class="glyphicon form-control-feedback" aria-hidden="true" id="Password1"></span>
</div>
@Html.ValidationMessageFor(m => m.Password, null, new { @class = "sr-only", id = "PasswordBlock" })
</div>
<div class="form-group">
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 col-lg-offset-1 col-md-offset-1 col-sm-offset-1 col-xs-offset-1 col-lg-offset-2 col-md-offset-2 col-sm-offset-2 col-xs-offset-2 content-font-size">
<label class="checkbox form control">
@Html.CheckBoxFor(m => m.RememberMe)
@Resource.RememberMe
</label>
</div>
</div>
<div class="form-group">
</div>
<div class="form-group">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 text-right content-font-size">
@Html.ActionLink(Resource.PasswordForgotten, "ForgotPassword")
</div>
</div>
}
该应用程序在我的计算机上运行正常,但是当在另一台计算机上使用时,当我尝试登录时,防伪验证失败:
[10:55:50 INF] Session started; Key:0a87a293-1bd0-6c85-ad7e-457b509dc406, Id:37160380-4c09-0044-e803-2f446ced3880
[10:55:50 INF] Request finished in 652.4502ms 200 text/html; charset=utf-8
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/css/contentcss.css
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/css/themes/base/themebase.css
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/js/knockout-custom-bindings.js
[10:55:50 INF] The file /css/contentcss.css was not modified
[10:55:50 INF] Request finished in 36.7042ms 304 text/css
[10:55:50 INF] Sending file. Request path: '/css/themes/base/themebase.css'. Physical path: 'D:\MyApp\wwwroot\css\themes\base\themebase.css'
[10:55:50 INF] Sending file. Request path: '/js/knockout-custom-bindings.js'. Physical path: 'D:\MyApp\wwwroot\js\knockout-custom-bindings.js'
[10:55:50 INF] Request finished in 73.9864ms 200 application/javascript
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/js/MyApp.js?dt=20200220105550
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/js/bootstrap.js
[10:55:50 INF] The file /js/bootstrap.js was not modified
[10:55:50 INF] Request finished in 74.3462ms 200 text/css
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/js/jquery.validate.js
[10:55:50 INF] Request finished in 16.995ms 304 application/javascript
[10:55:50 INF] Sending file. Request path: '/js/MyApp.js'. Physical path: 'D:\MyApp\wwwroot\js\MyApp.js'
[10:55:50 INF] Request finished in 24.518ms 200 application/javascript
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/js/jquery-3.4.1.js
[10:55:50 INF] The file /js/jquery-3.4.1.js was not modified
[10:55:50 INF] Request finished in 11.8633ms 304 application/javascript
[10:55:50 INF] The file /js/jquery.validate.js was not modified
[10:55:50 INF] Request finished in 34.9505ms 304 application/javascript
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/js/ui.js
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/css/fonts/ttf/vprounded-light-webfont.ttf
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/css/fonts/ttf/vprounded-regular-webfont.ttf
[10:55:50 INF] The file /js/ui.js was not modified
[10:55:50 INF] Sending file. Request path: '/css/fonts/ttf/vprounded-light-webfont.ttf'. Physical path: 'D:\MyApp\wwwroot\css\fonts\ttf\vprounded-light-webfont.ttf'
[10:55:50 INF] Request finished in 17.0987ms 304 application/javascript
[10:55:50 INF] Sending file. Request path: '/css/fonts/ttf/vprounded-regular-webfont.ttf'. Physical path: 'D:\MyApp\wwwroot\css\fonts\ttf\vprounded-regular-webfont.ttf'
[10:55:50 INF] Request finished in 4.8517ms 200 application/x-font-ttf
[10:55:50 INF] Request finished in 37.1005ms 200 application/x-font-ttf
[10:55:50 INF] Request starting HTTP/1.1 GET http://localhost:5000/js/modernizr-3.8.0.js
[10:55:50 INF] The file /js/modernizr-3.8.0.js was not modified
[10:55:50 INF] Request finished in 9.9437ms 304 application/javascript
[10:55:51 INF] Request starting HTTP/1.1 GET http://localhost:5000/images/favicon.ico
[10:55:51 INF] Sending file. Request path: '/images/favicon.ico'. Physical path: 'D:\MyApp\wwwroot\images\favicon.ico'
[10:55:51 INF] Request finished in 4.4223ms 200 image/x-icon
[10:55:57 INF] Request starting HTTP/1.1 POST http://localhost:5000/ application/x-www-form-urlencoded 253
[10:55:57 INF] Route matched with {action = "Login", controller = "Account", area = ""}. Executing controller action with signature System.Threading.Tasks.Task`1[Microsoft.AspNetCore.Mvc.ActionResult] Login(MyApp.Core.Models.Account.LoginViewModel, System.String) on controller MyApp.Core.Controllers.AccountController (MyApp.Core).
[10:55:57 INF] Antiforgery token validation failed. The required antiforgery cookie ".AspNetCore.Antiforgery.fKtywT1TTCk" is not present.
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The required antiforgery cookie ".AspNetCore.Antiforgery.fKtywT1TTCk" is not present.
at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext)
at Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync(AuthorizationFilterContext context)
[10:55:57 INF] Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter'.
[10:55:57 INF] Executing HttpStatusCodeResult, setting HTTP status code 400
[10:55:57 INF] Executed action MyApp.Core.Controllers.AccountController.Login (MyApp.Core) in 136.2078ms
[10:55:57 INF] Http Request Information:
很有趣,即使在另一台计算机上运行,页面源代码中也有一个防伪令牌。
虽然不能真正弄清楚为什么验证失败。
[编辑1]
好吧,这似乎是由于HTTPS起作用,但是很奇怪,它们是无关的。似乎没有意义,可能是Startup
中的配置有问题。
[编辑2]
然后我调试了防伪中间件:
- https://github.com/dotnet/aspnetcore/blob/master/src/Antiforgery/src/Internal/DefaultAntiforgery.cs#L275
- https://github.com/dotnet/aspnetcore/blob/master/src/Antiforgery/src/Internal/DefaultAntiforgery.cs#L155
- https://github.com/dotnet/aspnetcore/blob/master/src/Antiforgery/src/Internal/DefaultAntiforgeryTokenStore.cs#L41
看来:
var cookieToken = httpContext.Request.Cookies[_options.Cookie.Name];
实际上是null
...
这是在登录页面后面显示实际代码时的某种意外原因:
<form action="/" class="form-horizontal contentPane2" method="post" role="form"> <div class="tab" style="width: 100%">
<div id="TopHeader" class="documentTabHeaderTop"> </div>
<div class="container-fluid documentTitleHeader text-center documentTabHeaderTd-active">
<div class="col-xs-12 col-sm-12 col-lg-12 headImage"></div>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 col-lg-offset-1 col-md-offset-1 col-xs-offset-1 col-sm-offset-0 buttons-visible">
<div>
<input type="submit" id="ContinueButton" value="SEND" class="buttonItem buttonItem-valid">
</div>
</div>
</div>
<div class="form-group">
</div>
<div class="form-group has-feedback">
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 col-lg-offset-1 col-md-offset-1 col-sm-offset-1 col-xs-offset-1">
<input aria-describedby="EMailStatus" class="form-control" data-val="true" data-val-email="The Login field is not a valid e-mail address." data-val-required="The Login field is required." id="Email" name="Email" placeholder="Login" type="text" value="">
<span class="glyphicon form-control-feedback" aria-hidden="true" id="Email1"></span>
</div>
<span class="field-validation-valid sr-only" data-valmsg-for="Email" data-valmsg-replace="true" id="EMailStatus"></span>
</div>
<div class="form-group has-feedback">
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 col-lg-offset-1 col-md-offset-1 col-sm-offset-1 col-xs-offset-1">
<input aria-describedby="PasswordBlock" class="form-control" data-val="true" data-val-required="The Password field is required." id="Password" name="Password" placeholder="Password" type="password">
<span class="glyphicon form-control-feedback" aria-hidden="true" id="Password1"></span>
</div>
<span class="field-validation-valid sr-only" data-valmsg-for="Password" data-valmsg-replace="true" id="PasswordBlock"></span>
</div>
<div class="form-group">
<div class="col-lg-10 col-md-10 col-sm-10 col-xs-10 col-lg-offset-1 col-md-offset-1 col-sm-offset-1 col-xs-offset-1 col-lg-offset-2 col-md-offset-2 col-sm-offset-2 col-xs-offset-2 content-font-size">
<label class="checkbox form control">
<input data-val="true" data-val-required="The Remember me? field is required." id="RememberMe" name="RememberMe" type="checkbox" value="true">
Remember me
</label>
</div>
</div>
<div class="form-group">
</div>
<div class="form-group">
<div class="col-lg-12 col-md-12 col-sm-12 col-xs-12 text-right content-font-size">
<a href="/ForgotPassword">Forgot your password?</a>
</div>
</div>
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8CvSe49ypctKiIz481LO88tJwZpiwj8bwXlcfyHoKa__RWLQgNEgyiO1xNbDAV0C7SjWeqPJOWciiYMBjfXb039cW50GwqNC5561LzuOYkM8umGaqGo3cV2X935LY5FrVj5OUkPzyFwQp7Y4vCcOGuE"><input name="RememberMe" type="hidden" value="false"></form>
好吧我花了一些时间才弄清楚,但是长话短说...当检查整个反伪造令牌过程shenanigan的源代码时,似乎对cookie的设置方式进行了一致性检查。此处:https://github.com/dotnet/aspnetcore/blob/master/src/Antiforgery/src/Internal/DefaultAntiforgery.cs#L275
private void CheckSSLConfig(HttpContext context) { if (_options.Cookie.SecurePolicy == CookieSecurePolicy.Always && !context.Request.IsHttps) { throw new InvalidOperationException(Resources.FormatAntiforgery_RequiresSSL( string.Join(".", nameof(AntiforgeryOptions), nameof(AntiforgeryOptions.Cookie), nameof(CookieBuilder.SecurePolicy)), nameof(CookieSecurePolicy.Always))); } }
因为我的cookie配置是...:
app.UseCookiePolicy(new CookiePolicyOptions
{
HttpOnly = HttpOnlyPolicy.Always,
Secure = CookieSecurePolicy.Always
});
然后有点把不安全的http请求弄乱了。
因此,我故意使配置与请求所使用的协议方案相匹配:
app.UseCookiePolicy(new CookiePolicyOptions
{
HttpOnly = HttpOnlyPolicy.Always,
Secure = CookieSecurePolicy.SameAsRequest
});
现在它就像一种魅力!
以上是关于为什么具有相同防伪验证功能的同一个ASP.NET Core应用程序在一台计算机上而不是另一台计算机上工作?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 ASP.NET 和 iframe 跨域对用户进行身份验证?
Asp.net Mvc:Jquery post 数组 + 防伪令牌
如何在无视图 WebAPI ASP.NET Core 应用程序中使用 [Authorize] 和防伪?