ASP.NET WebForms向ASP.NET Core 6跨站POST登录遇HTTP 405错误排查
问题描述
我有两个独立的门户站点,均需用户登录后方可使用服务:一个基于ASP.NET WebForms构建,另一个基于ASP.NET Core 6构建。两站点部署在同一服务器的IIS上,我希望通过从WebForms站点向Core站点POST用户名和密码,实现用户在两个服务间自动登录。
我尝试在WebForms站点中使用如下代码提交数据:
<html> <head id="Head1" runat="server"> <title></title> </head> <body> <form action="https://xxx.xxxx.xxx/xxx/Login/login" method="post" id="sub" > <div style="display:none;"> <input type="text" value="111111" name="Db_UserName" id="Db_UserName" runat="server" /> <input type="text" value="222222" name="Password" id="Password" runat="server" /> </div> </form> <script type="text/javascript"> document.getElementById('sub').submit(); </script> </body> </html>
并在ASP.NET Core 6的Login控制器中使用如下代码接收数据:
[HttpPost] public IActionResult login(LoginViewModel model) { TempData["msg"]= model.Db_UserName; return RedirectToAction(nameof(Index)); }
但出现错误:
This page isn’t working. If the problem continues, contact the site owner.
HTTP ERROR 405
请问问题出在哪里?该如何解决?
问题原因及解决方案
核心原因
- 跨域请求拦截:即使两站点在同一服务器,只要域名、端口或应用路径不同,就属于不同源。浏览器的同源策略会阻止客户端发起的跨域POST请求,直接触发405 Method Not Allowed错误。
- 路由匹配异常:ASP.NET Core路由默认大小写不敏感,但如果控制器/方法的路由模板与请求URL的大小写不匹配,或路由配置存在严格约束,也可能导致请求无法匹配到目标Action,返回405。
分步解决方案
1. 配置ASP.NET Core的CORS策略
在Core项目的Program.cs中添加CORS支持,明确允许WebForms站点的跨域请求:
var builder = WebApplication.CreateBuilder(args); // 添加CORS策略 builder.Services.AddCors(options => { options.AddPolicy("AllowWebFormsOrigin", policy => { // 替换为WebForms站点的实际域名(如http://your-webforms-site.com) policy.WithOrigins("http://your-webforms-url") .AllowAnyHeader() .AllowAnyMethod(); }); }); builder.Services.AddControllersWithViews(); var app = builder.Build(); // 启用CORS(必须放在UseRouting之后、UseAuthorization之前) app.UseCors("AllowWebFormsOrigin"); app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
2. 修正路由匹配一致性
- 检查
Login控制器是否添加了路由特性,比如[Route("[controller]/[action]")],确保/Login/login能正确匹配到目标Action。 - 统一URL与方法名的大小写:将Core控制器的方法名改为
Login(首字母大写),或把WebForms表单的action调整为https://xxx.xxxx.xxx/xxx/Login/Login,避免大小写匹配问题。
3. 改用服务器端POST(更安全,规避跨域限制)
客户端自动提交跨域表单易被浏览器拦截,建议在WebForms后台通过服务器端发起POST请求:
protected void Page_Load(object sender, EventArgs e) { string coreLoginUrl = "https://xxx.xxxx.xxx/xxx/Login/login"; string username = "111111"; string password = "222222"; // 构造POST请求 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(coreLoginUrl); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; // 编码POST参数 string postData = $"Db_UserName={Uri.EscapeDataString(username)}&Password={Uri.EscapeDataString(password)}"; byte[] byteArray = Encoding.UTF8.GetBytes(postData); request.ContentLength = byteArray.Length; // 写入请求数据 using (Stream dataStream = request.GetRequestStream()) { dataStream.Write(byteArray, 0, byteArray.Length); } // 获取响应并跳转至Core站点首页 using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) { // 若需共享登录状态,可在此获取Core站点的Cookie并附加到当前响应 Response.Redirect("https://xxx.xxxx.xxx/xxx/Index"); } }
这种服务器端请求不会触发浏览器跨域限制,因为请求是从服务器到服务器的。
4. 可选:配置Cookie共享实现单点登录
若要让两站点共享登录状态,需完成以下配置:
- IIS配置:确保两站点的应用程序池使用相同的标识,或配置共享的机器密钥。
- ASP.NET Core配置:指定共享Cookie名称、域名和数据保护密钥:
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.Cookie.Name = ".SharedAuthCookie"; options.Cookie.Domain = ".your-domain.com"; // 两站点需属于同一主域名的子域 options.TicketDataFormat = new TicketDataFormat( new DataProtectorShim( DataProtectionProvider.Create(new DirectoryInfo(@"\\server\shared-keys-folder")) .CreateProtector("Microsoft.AspNetCore.Authentication.Cookies", CookieAuthenticationDefaults.AuthenticationScheme, "v2"))); });
WebForms站点也需配置相同的Cookie名称和机器密钥,实现登录状态跨站点共享。
内容的提问来源于stack exchange,提问作者Mohammed Allouh
相关产品推荐
相关产品推荐

