ASP.NET Core MVC 检查授权 post 返回

ASP.NET Core MVC check Authorization on post back

我认为标题可能有点歪曲,但是,这是我的问题和 objective。我正在使用 ASP.NET Core 3.1 MVC 开发应用程序。我需要限制用户对某些区域、页面等的访问。我已经在 Startup.cs 文件中完成了此操作,并将 [Authorize] 属性添加到我的管理控制器。但是,我似乎无法弄清楚的是:如果管理员在该用户登录时删除了该用户的管理权限,并且他们试图访问受保护的页面,我该如何阻止他们访问该页面?我知道合乎逻辑的答案可能是让用户注销并重新登录,但是,在这种情况下不需要这样做。

文件Startup.cs(代码片段)

public void ConfigureServices(IServiceCollection services)
{
    //Configuration
    services.Configure<HHConfig>(Configuration.GetSection("App"));
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer( 
        Configuration.GetConnectionString("DefaultConnection"))); 
    services.AddIdentity<ApplicationUser, IdentityRole>(options =>
    {
        options.Password.RequiredLength = 8;
        options.Password.RequiredUniqueChars = 1;
        options.SignIn.RequireConfirmedAccount = true;
        })
        .AddRoles<IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();            
        services.AddControllersWithViews();
        services.AddRazorPages(options => {
        options.Conventions.AuthorizeFolder("/Administration");
    });

    services.AddMvc().AddRazorPagesOptions(options =>
    {
        options.Conventions.AddAreaPageRoute("Identity", "/Account/Login", "/Account/Login");
    });

    //Transient and Scoped Services Here
    services.AddTransient<ApplicationDbContext>();
    services.AddScoped<IEmailManager, EmailManager>();
}

管理控制器

[Authorize(Roles = "Admin")]
public class AdministrationController : Controller
{
    private readonly RoleManager<IdentityRole> roleManager;
    private readonly UserManager<ApplicationUser> userManager;
    private SignInManager<ApplicationUser> signInManager { get; }
    private readonly IEmailManager emailManager;

    public AdministrationController(RoleManager<IdentityRole> roleManager,UserManager<ApplicationUser> userManager,SignInManager<ApplicationUser> signInManager, IEmailManager emailMgr)
    {
        this.roleManager = roleManager;
        this.userManager = userManager;
        this.signInManager = signInManager;
        emailManager = emailMgr;
    }        
}     

您 运行 遇到的问题是用户的声明存储在用户浏览器的 cookie 中。您需要做的是确保在更新用户的声明时更新 cookie。一种方法是您可以在关键页面上刷新用户的 sign-in。

这可以通过以下方法完成:

  1. 注册一个 UserClaimsPrincipalFactory 以便每次 SignInManager 登录用户时,都会创建声明。

     services.AddScoped<IUserClaimsPrincipalFactory<ApplicationUser>, UserClaimService>();
    
  2. 实现自定义 UserClaimsPrincipalFactory<TUser, TRole> 如下所示

     public class UserClaimService : UserClaimsPrincipalFactory<ApplicationUser, ApplicationRole>
     {
         private readonly ApplicationDbContext _dbContext;
    
         public UserClaimService(ApplicationDbContext dbContext, UserManager<ApplicationUser> userManager, RoleManager<ApplicationRole> roleManager, IOptions<IdentityOptions> optionsAccessor) : base(userManager, roleManager, optionsAccessor)
         {
             _dbContext = dbContext;
         }
    
         public override async Task<ClaimsPrincipal> CreateAsync(ApplicationUser user)
         {
             var principal = await base.CreateAsync(user);
    
             // Get user claims from DB using dbContext
    
             // Add claims
             ((ClaimsIdentity)principal.Identity).AddClaim(new Claim("claimType", "some important claim value"));
    
             return principal;
         }
     }
    
  3. 稍后在您的应用程序中,当您更改数据库中的某些内容并希望将此反映给您经过身份验证和登录的用户时,以下几行可实现此目的:

     var user = await _userManager.GetUserAsync(User);
     await _signInManager.RefreshSignInAsync(user);
    

这将让用户在没有任何交互的情况下再次登录,并确保向他们显示 up-to-date 内容。虽然这不是同一个问题,但 this question 中还有其他答案可以帮助解决这个问题。我必须将此答案归功于此。