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

如何让ASP.NET Identity识别自定义MVC结构替代默认Razor页面?

解决Identity全局使用自定义MVC控制器的问题

问题描述

项目中使用Identity包并引入自定义MVC结构的Identity代码,但Identity仍调用默认Razor页面逻辑。例如角色验证未通过时,跳转至默认登录页而非自定义的Account控制器Login方法,仅部分场景能跳转至自定义MVC代码,无法全局生效。

项目现有Program.cs代码

using App;
using App.Services;
using m01_Start;
using m01_Start.Models;
using m01_Start.Services;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();

builder.Services.AddRazorPages();
// add services
builder.Services.AddSingleton<ProductService>();
builder.Services.AddSingleton<PlanetService>();
builder.Services.AddSingleton<IdentityErrorDescriber, AppIdentityErrorDescriber>();


// Setup dbcontext
builder.Services.AddDbContext<AppDbContext>(options =>
        {
             string conntectString = builder.Configuration.GetConnectionString("AppMvcConnectString");
             // System.Console.WriteLine(conntectString);
             options.UseSqlServer(conntectString);
        });

// add identity
builder.Services.AddDefaultIdentity<AppUser>()
                       .AddRoles<IdentityRole>()      // add fix add role error
                       .AddEntityFrameworkStores<AppDbContext>()
                    //    .AddDefaultTokenProviders()
                       ;

// Config Identity 
builder.Services.Configure<IdentityOptions>(options =>
        {
             options.Password.RequireDigit = false; 
             options.Password.RequireLowercase = false; 
             options.Password.RequireNonAlphanumeric = false; 
             options.Password.RequireUppercase = false;
             options.Password.RequiredLength = 3;  
             options.Password.RequiredUniqueChars = 1; 
             options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(1); 
             options.Lockout.MaxFailedAccessAttempts = 3;
             options.Lockout.AllowedForNewUsers = true;
             // Cấu hình về User.
             options.User.AllowedUserNameCharacters = // các ký tự đặt tên user
                 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
             options.User.RequireUniqueEmail = true;  
             options.SignIn.RequireConfirmedEmail = true;            
             options.SignIn.RequireConfirmedPhoneNumber = false;     
             options.SignIn.RequireConfirmedAccount = true;
        });

var app = builder.Build();

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

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.AddStatusCodePage();

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

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

app.Run();

解决方案

1. 替换Identity服务注册方式

AddDefaultIdentity会自动引入默认Razor Pages版Identity UI,改用AddIdentity手动注册服务,避免依赖默认页面:

修改Identity注册代码:

// 替换原AddDefaultIdentity代码
builder.Services.AddIdentity<AppUser, IdentityRole>()
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<AppDbContext>()
    .AddDefaultTokenProviders();

2. 配置Identity跳转路径

通过ConfigureApplicationCookie指定登录、权限拒绝等场景的MVC路由:

在Program.cs中添加以下配置:

builder.Services.ConfigureApplicationCookie(options =>
{
    // 登录跳转路径,指向自定义Account控制器的Login方法
    options.LoginPath = "/Account/Login";
    // 权限不足时跳转路径
    options.AccessDeniedPath = "/Account/AccessDenied";
    // 登出跳转路径
    options.LogoutPath = "/Account/Logout";
    
    // Cookie基础配置(可选)
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
    options.SlidingExpiration = true;
});

3. 清理不必要的Razor Pages依赖(可选)

若项目无需Razor Pages,移除以下代码:

// 移除Razor Pages服务注册
// builder.Services.AddRazorPages();

// 移除Razor Pages路由映射
// app.MapRazorPages();

4. 验证自定义Account控制器路由

确保自定义Account控制器的Action路由正确,示例:

public class AccountController : Controller
{
    private readonly SignInManager<AppUser> _signInManager;

    public AccountController(SignInManager<AppUser> signInManager)
    {
        _signInManager = signInManager;
    }

    [HttpGet]
    public IActionResult Login(string returnUrl = null)
    {
        ViewData["ReturnUrl"] = returnUrl;
        return View();
    }

    [HttpPost]
    public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
    {
        returnUrl ??= Url.Content("~/");
        
        if (ModelState.IsValid)
        {
            var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, lockoutOnFailure: false);
            if (result.Succeeded)
            {
                return LocalRedirect(returnUrl);
            }
            ModelState.AddModelError(string.Empty, "无效的登录尝试。");
        }
        
        return View(model);
    }

    // 其他如AccessDenied、Logout等方法...
}

同时确认Views/Account目录下存在对应的视图文件(如Login.cshtml)。

5. 保持路由优先级

确保MVC控制器路由在Razor Pages路由之前注册,现有代码中已先执行MapAreaControllerRoute和MapControllerRoute,再执行MapRazorPages,此顺序正确,无需修改。

修改后的完整Program.cs示例

using App;
using App.Services;
using m01_Start;
using m01_Start.Models;
using m01_Start.Services;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();

// 若无需Razor Pages,可移除该行
// builder.Services.AddRazorPages();

// add services
builder.Services.AddSingleton<ProductService>();
builder.Services.AddSingleton<PlanetService>();
builder.Services.AddSingleton<IdentityErrorDescriber, AppIdentityErrorDescriber>();

// Setup dbcontext
builder.Services.AddDbContext<AppDbContext>(options =>
{
    string conntectString = builder.Configuration.GetConnectionString("AppMvcConnectString");
    options.UseSqlServer(conntectString);
});

// 替换为AddIdentity注册Identity服务
builder.Services.AddIdentity<AppUser, IdentityRole>()
    .AddRoles<IdentityRole>()
    .AddEntityFrameworkStores<AppDbContext>()
    .AddDefaultTokenProviders();

// Config Identity 
builder.Services.Configure<IdentityOptions>(options =>
{
    options.Password.RequireDigit = false; 
    options.Password.RequireLowercase = false; 
    options.Password.RequireNonAlphanumeric = false; 
    options.Password.RequireUppercase = false;
    options.Password.RequiredLength = 3;  
    options.Password.RequiredUniqueChars = 1; 
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(1); 
    options.Lockout.MaxFailedAccessAttempts = 3;
    options.Lockout.AllowedForNewUsers = true;
    options.User.AllowedUserNameCharacters = 
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
    options.User.RequireUniqueEmail = true;  
    options.SignIn.RequireConfirmedEmail = true;            
    options.SignIn.RequireConfirmedPhoneNumber = false;     
    options.SignIn.RequireConfirmedAccount = true;
});

// 配置Identity跳转路径
builder.Services.ConfigureApplicationCookie(options =>
{
    options.LoginPath = "/Account/Login";
    options.AccessDeniedPath = "/Account/AccessDenied";
    options.LogoutPath = "/Account/Logout";
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(30);
    options.SlidingExpiration = true;
});

var app = builder.Build();

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

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.AddStatusCodePage();

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

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

// 若无需Razor Pages,可移除该行
// app.MapRazorPages();

app.Run();

内容的提问来源于stack exchange,提问作者Kuj9xst3

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 01:10:03