You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部署在GoDaddy的ASP.NET Core 6应用认证/会话超时问题求助

ASP.NET Core 6 部署GoDaddy后认证/会话超时问题求助

我基于ASP.NET Core 6开发的应用在本地运行完全正常,但部署到GoDaddy服务器环境后,未授权用户尝试访问部分功能时会出现认证或会话超时问题。已进行大量排查仍无法定位根因,请求技术协助。

应用Program.cs代码

using Portal._keenthemes.libs;
using Portal._keenthemes;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Portal.Data;
using PortalServices.Context;
using PortalServices.Models;
using PortalServices.Interfaces;
using Microsoft.AspNetCore.Localization;
using System.Globalization;
using Portal.Security;
using PortalServices.Services;
using Portal.Data.Data;
using PortalServices.Models.Email;
using Portal.GlobalValues;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Options;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");

builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(connectionString));

builder.Services.AddDefaultIdentity<User>(
    options => options.SignIn.RequireConfirmedAccount = true
) 
       .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddTokenProvider<EmailConfirmationTokenProvider<User>>("email_confirmation_provider");

builder.Services.AddDbContext<PortalContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.ConfigureApplicationCookie(options =>
{
    options.LoginPath = "/Account/Login";
    options.ExpireTimeSpan = TimeSpan.FromDays(365);
    options.SlidingExpiration = false;
});

builder.Services.Configure<SecurityStampValidatorOptions>(o => o.ValidationInterval = TimeSpan.FromHours(7));


builder.Services.AddScoped<IKTTheme, KTTheme>();
builder.Services.AddSingleton<IKTBootstrapBase, KTBootstrapBase>();

builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");

builder.Services.AddControllersWithViews()
    .AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.Suffix)
    .AddDataAnnotationsLocalization();

builder.Services.Configure<RequestLocalizationOptions>(options =>
{
    options.DefaultRequestCulture = new RequestCulture("en-NZ");
    options.SupportedCultures = new List<CultureInfo> { new CultureInfo("en-NZ") };
    options.RequestCultureProviders = new List<IRequestCultureProvider>();
});

builder.Services.Configure<IdentityOptions>(options =>
{
    options.Password.RequireDigit = true;
    options.Password.RequiredLength = 6;
    options.Password.RequireNonAlphanumeric = false;

    options.SignIn.RequireConfirmedAccount = false; 

    options.User.RequireUniqueEmail = true;
});

builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromHours(15);
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("Admin", policy =>
    {
        policy.AddRequirements(new AdminRole());
        policy.RequireAuthenticatedUser();
    });
});

IConfiguration configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();


builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
builder.Services.Configure<SmtpSettings>(configuration.GetSection("SmtpSettings"));

builder.Services.AddScoped<IPortalContext, PortalContext>();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<ICategoriesService, CategoriesService>();
builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddScoped<IEmailService, EmailService>();
builder.Services.AddScoped<IJobService, JobService>();
builder.Services.AddHostedService<ScheduledService>();



var app = builder.Build();

KTThemeSettings.init(configuration);

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios
    app.UseHsts();
}

app.UseSession();
app.UseRequestLocalization();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.UseThemeMiddleware();

app.MapControllerRoute(
    name: "Identity",
    pattern: "{area:exists}/{controller=Identity}/{action=Logout}");

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "Admin",
        pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}",
        defaults: new { area = "Admin" }
    );

    endpoints.MapGet("/", async context =>
    {
        if (context.User.Identity.IsAuthenticated)
        {
            var userManager = context.RequestServices.GetRequiredService<UserManager<User>>();
            var user = await userManager.GetUserAsync(context.User);

            if(user == null)
            {
                context.Response.Redirect("/Account/Login");
            }
            else if (await userManager.IsInRoleAsync(user, "Admin"))
            {
                context.Response.Redirect("/Admin");
                return;
            } else if (await userManager.IsInRoleAsync(user, "Seller"))
            {
                context.Response.Redirect("/Seller");
                return;
            } else if (await userManager.IsInRoleAsync(user, "Freelancer"))
            {
                context.Response.Redirect("/Freelancer");
                return;
            }
        }

        context.Response.Redirect("/Home/Index");
    });
});

app.MapRazorPages();


using (var scope = app.Services.CreateScope())
{
    await DbSeeder.SeedRoleAndAdminAsync(scope.ServiceProvider);
}

app.Run();


public class EmailConfirmationTokenProvider<TUser> : DataProtectorTokenProvider<TUser> where TUser : class
{
    public EmailConfirmationTokenProvider(IDataProtectionProvider dataProtectionProvider,
        IOptions<EmailConfirmationTokenProviderOptions> options, ILogger<EmailConfirmationTokenProvider<TUser>> logger)
        : base(dataProtectionProvider, options, logger)
    {
    }
}

public class EmailConfirmationTokenProviderOptions : DataProtectionTokenProviderOptions
{ }

排查方向及解决方案建议

  • 会话存储优化:当前使用AddDistributedMemoryCache(),GoDaddy共享宿主环境下应用进程可能被频繁回收,导致内存缓存丢失。建议改用SQL Server分布式缓存:

    builder.Services.AddDistributedSqlServerCache(options =>
    {
        options.ConnectionString = connectionString;
        options.SchemaName = "dbo";
        options.TableName = "SessionCache";
    });
    

    执行对应的数据库迁移脚本创建SessionCache表。

  • Cookie配置修正:生产环境需确保Cookie安全属性正确,适配GoDaddy代理环境:

    builder.Services.ConfigureApplicationCookie(options =>
    {
        options.LoginPath = "/Account/Login";
        options.ExpireTimeSpan = TimeSpan.FromDays(365);
        options.SlidingExpiration = false;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.SameSite = SameSiteMode.Lax;
        // 若使用子域名,添加:options.Cookie.Domain = ".yourdomain.com";
    });
    
    builder.Services.Configure<SessionOptions>(options =>
    {
        options.IdleTimeout = TimeSpan.FromHours(15);
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Cookie.SameSite = SameSiteMode.Lax;
    });
    
  • 数据保护密钥持久化:ASP.NET Core数据保护密钥默认存储在本地,应用重启后密钥丢失会导致Cookie验证失败。配置密钥持久化到GoDaddy允许的目录:

    builder.Services.AddDataProtection()
        .PersistKeysToFileSystem(new DirectoryInfo(@"D:\home\site\wwwroot\App_Data\Keys"))
        .SetApplicationName("YourApplicationName");
    

    确保该目录有读写权限。

  • 反向代理头部信任:GoDaddy使用反向代理,需配置应用信任转发的头部,避免HTTPS重定向或认证错误:

    builder.Services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
        // 添加GoDaddy代理IP到已知代理列表,可从GoDaddy文档获取
        options.KnownProxies.Add(IPAddress.Parse("xxx.xxx.xxx.xxx"));
    });
    

    在中间件管道最前面添加:

    app.UseForwardedHeaders();
    
  • 中间件顺序调整:Session中间件需在Routing和Authentication之前,调整管道顺序为:

    app.UseForwardedHeaders();
    app.UseHsts();
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseSession();
    app.UseRequestLocalization();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    
  • 应用池回收配置:登录GoDaddy控制面板,调整应用池回收规则:

    • 取消固定时间回收,改为按需回收
    • 提高内存/CPU回收阈值
    • 设置回收时间为非业务高峰时段
  • 启用详细日志:修改appsettings.json的Logging配置,记录认证和Session相关日志:

    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft.AspNetCore.Authentication": "Debug",
            "Microsoft.AspNetCore.Session": "Debug",
            "Microsoft.AspNetCore.DataProtection": "Debug"
        }
    }
    

    查看GoDaddy日志目录(D:\home\LogFiles\http\RawLogs)中的错误信息,定位具体问题。

内容的提问来源于stack exchange,提问作者Rashid Zafar Iqbal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 11:32:03