簡體   English   中英

User.IsInRole 在 ASP.NET Core 中不返回任何內容(實現了存儲庫模式)

[英]User.IsInRole returns nothing in ASP.NET Core (Repository Pattern implemented)

我有一個具有以下配置的 ASP.NET Core(完整的 .NET Framework)應用程序:

啟動文件

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>(p => {
        p.Password.RequireDigit = true;
        p.Password.RequireNonAlphanumeric = false;
        p.Password.RequireUppercase = true;
        p.Password.RequiredLength = 5;
    })
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

    services.AddMvc();

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
    services.AddTransient<IDbFactory, DbFactory>();
    services.AddTransient<IUnitOfWork, UnitOfWork>();

    services.AddTransient<IUserRepository, UserRepository>();
    services.AddTransient<IUserService, UserService>();
}

ApplicationUser 擴展自 IdentityUser 和 ApplicationDbContext 擴展 IdentityDbContext

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext()
        : base()
    {
    }

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    public virtual void Commit()
    {
        base.SaveChanges();
    }

    protected override void OnConfiguring(DbContextOptionsBuilder builder)
    {
        base.OnConfiguring(builder);

        builder.UseSqlServer("connection string here");
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        // Customize the ASP.NET Identity model and override the defaults if needed.
        // For example, you can rename the ASP.NET Identity table names and more.
        // Add your customizations after calling base.OnModelCreating(builder);

        // Configure model
        // Identity
        new Configuration.Identity.ApplicationUserConfiguration(builder.Entity<ApplicationUser>());
        new Configuration.Identity.ApplicationUserProfileConfiguration(builder.Entity<ApplicationUserProfile>());
        new Configuration.Identity.RoleConfiguration(builder.Entity<IdentityRole>());
        new Configuration.Identity.RoleClaimConfiguration(builder.Entity<IdentityRoleClaim<string>>());
        new Configuration.Identity.ApplicationUserRoleConfiguration(builder.Entity<IdentityUserRole<string>>());
        new Configuration.Identity.ApplicationUserClaimConfiguration(builder.Entity<IdentityUserClaim<string>>());
        new Configuration.Identity.ApplicationUserLoginConfiguration(builder.Entity<IdentityUserLogin<string>>());
        new Configuration.Identity.ApplicationUserTokenConfiguration(builder.Entity<IdentityUserToken<string>>());
    }
}

這是我的演示數據:

角色表

角色表

用戶表

用戶表

用戶角色表

用戶角色表

在我的登錄操作中,我有以下內容:

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;
    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, lockoutOnFailure: false);
        if (result.Succeeded)
        {
            if (User.IsInRole("Admin"))
            {
                return RedirectToAction("Index", "Home", new { area = "Admin" });
            }
            return RedirectToAction("Index", "Home");
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning(2, "User account locked out.");
            return View("Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return View(model);
        }
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

我想要實現的是登錄后將用戶重定向到某個區域。

我目前面臨的問題是函數User.IsInRole("Admin")返回 false 並且在調試模式下,如果我查看用戶管理器,當前用戶沒有加載角色(計數 = 0)。

任何想法將不勝感激。

更新 1

忽略角色 ID 原因是錯誤的。 事實上,用戶被映射到了正確的值。

User.IsInRole正在檢查 cookie。 但是您在登錄時在同一個 http 請求中進行檢查。 Cookie 尚不存在 - 它將在回復或下一個請求中可用。

此時您需要使用ApplicationUserManager.IsInRoleAsync(TKey userId, string role)來檢查數據庫。

如果有人(如我)在 .Net Core 2.1 中為此苦苦掙扎,此鏈接可能會有所幫助

簡而言之,如果您像這樣使用AddDefaultIdentity

services.AddDefaultIdentity<ApplicationUser>()
            .AddEntityFrameworkStores<ApplicationDbContext>();

那么角色將無法工作,因為它們沒有在 DefaultIdentity 中實現。

對我有用的是將其替換為:

services.AddIdentity<ApplicationUser, IdentityRole>()
            .AddRoleManager<RoleManager<IdentityRole>>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultUI()
            .AddDefaultTokenProviders();

此外,如果您在上述修復之前登錄,請注銷並再次登錄,以便刷新身份聲明。 現在它應該可以工作了。

經過數小時的搜索,我意識到在使用 Azure Active Directory 和角色時可以使用 ASP.Net Core

  User.HasClaim(ClaimTypes.Role,"admin");

這不

  User.IsInRole("admin");

從 .Net Core 2.1(也適用於 3.1)開始, AddDefaultIdentity與調用相同:

  • AddIdentity
  • AddDefaultUI
  • AddDefaultTokenProviders

要添加角色功能,請轉到ConfigureServices下的Startup.cs ,您可以像這樣使用.AddRoles

services.AddDefaultIdentity<IdentityUser>()
    .AddRoles<IdentityRole>()            //<-- This line
    .AddEntityFrameworkStores<ApplicationDbContext>();

這就是所需要的。 正如上面提到的那樣,注銷並重新登錄至關重要。

為了記錄(並且只是為了測試),我嘗試了services.AddIdentity

IServiceCollection 不包含“AddIdentity”的定義...

services.AddIdentityCore (在調試和顯示頁面之前沒有錯誤):

InvalidOperationException: 未指定 authenticationScheme,也未找到 DefaultChallengeScheme。 可以使用 AddAuthentication(string defaultScheme) 或 AddAuthentication(Action configureOptions) 設置默認方案。

可能還有更多方法可以讓后兩者正常工作,但我為AddDefaultIdentity發布的代碼是我需要的所有代碼,以便讓User.IsInRole和其他角色功能在 .NET Core 2.1 和 3.1 中工作,到目前為止。

我還發現了與 Kaptain Babbalas 相同的問題,並發現在 OnTokenValidated 中手動重新添加角色會使 User.Claims 的結果加倍,但會導致 User.IsInRole 起作用

options.Events = new OpenIdConnectEvents
{
    OnTokenValidated = (context) =>
    {
        var claims = new List<Claim>();
        foreach (var claim in context.Principal.Claims)
        {
            if (claim.Type == ClaimTypes.Role) claims.Add(new Claim(ClaimTypes.Role, claim.Value));
        }

        var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        context.Principal.AddIdentity(claimsIdentity);

        return Task.CompletedTask;
    }
};

User.IsInRole()SignIn之后處理下一個 Request 在您的代碼中, SignInUser.IsInRole()同一個 Request中執行。 因此,要應用手動重定向,您可以將身份驗證代碼放在另一個操作中,然后從Login()操作重定向到該操作,如下所示:

public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;
    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, set lockoutOnFailure: true
    var result = await _signInManager.PasswordSignInAsync(model.Username, model.Password, model.RememberMe, lockoutOnFailure: false);
    if (result.Succeeded)
    {
        return RedirectToAction("ObeyMyOrder");
    }
}

public async Task<IActionResult> ObeyMyOrder()
{
        if (User.IsInRole("Admin"))
        {
            return RedirectToAction("Index", "Home", new { area = "Admin" });
        }
        return RedirectToAction("Index", "Home");
}

現在User.IsInRole()將起作用。

就我而言,當用戶已經登錄時,我已將用戶添加到數據庫中的角色。注銷並再次登錄解決了該問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM