User.IsInRole在ASP.NET Core中没有返回任何内容(已实现存储库模式)

时间:2016-10-20 10:00:33

标签: c# asp.net-core asp.net-identity

我有一个ASP.NET Core(完整.NET Framework)应用程序,其配置如下:

Startup.cs

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>>());
    }
}

这是我的演示数据:

角色表

Role table

用户表

User table

UserRole表

UserRole table

在我的登录操作中,我有以下内容:

[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并且在调试模式下,如果我查看用户管理器,当前用户没有加载角色(Count = 0)。

任何想法都会受到赞赏。

更新1

忽略角色ID原因是错误的。事实上,用户使用正确的值进行映射。

7 个答案:

答案 0 :(得分:16)

User.IsInRole正在检查Cookie。但是您在登录时在同一个http请求中检查此内容。 Cookie根本就不存在 - 它将在回复或下一个请求中提供。

此时您需要使用ApplicationUserManager.IsInRoleAsync(TKey userId, string role)来检查数据库。

答案 1 :(得分:7)

经过数小时的搜索后,我在使用Azure Active Directory和角色

时意识到ASP.Net Core的这项工作
Option Explicit

Sub ExportByName()
Dim unique(1000) As String
Dim wb(1000) As Workbook
Dim ws As Worksheet
Dim x As Long, y As Long, ct As Long, uCol As Long

On Error GoTo ErrHandler

Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual

'Your main worksheet
Set ws = ActiveWorkbook.Sheets("Sheet1")

'Column J
uCol = 10

ct = 0

'get a unique list of users
For x = 2 To ws.Cells(ws.Rows.Count, uCol).End(xlUp).Row
    If CountIfArray(ActiveSheet.Cells(x, uCol), unique()) = 0 Then
        unique(ct) = ActiveSheet.Cells(x, uCol).Text
        ct = ct + 1
    End If
Next x

'loop through the unique list
For x = 0 To ws.Cells(ws.Rows.Count, uCol).End(xlUp).Row - 1

    If unique(x) <> "" Then
        'add workbook
        Set wb(x) = Workbooks.Add

        'copy header row
        ws.Range(ws.Cells(1, 1), ws.Cells(1, uCol)).Copy wb(x).Sheets(1).Cells(1, 1)

        'loop to find matching items in ws and copy over
        For y = 2 To ws.Cells(ws.Rows.Count, uCol).End(xlUp).Row
            If ws.Cells(y, uCol) = unique(x) Then

                'copy full formula over    
                'ws.Range(ws.Cells(y, 1), ws.Cells(y, uCol)).Copy wb(x).Sheets(1).Cells(WorksheetFunction.CountA(wb(x).Sheets(1).Columns(uCol)) + 1, 1)

                'to copy and paste values
                ws.Range(ws.Cells(y, 1), ws.Cells(y, uCol)).Copy
                wb(x).Sheets(1).Cells(WorksheetFunction.CountA(wb(x).Sheets(1).Columns(uCol)) + 1, 1).PasteSpecial (xlPasteValues)

            End If
        Next y

        'autofit
        wb(x).Sheets(1).Columns.AutoFit

        'save when done
        wb(x).SaveAs ThisWorkbook.Path & "\" & unique(x) & " " & Format(Now(), "mm-dd-yy")
        'wb(x).Close SaveChanges:=True

    Else
        'once reaching blank parts of the array, quit loop
        Exit For
    End If

Next x

Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic

ErrHandler:
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic

End Sub

Public Function CountIfArray(lookup_value As String, lookup_array As Variant)
CountIfArray = Application.Count(Application.Match(lookup_value, lookup_array, 0))
End Function

这不是

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

答案 2 :(得分:5)

如果有人(像我一样)在.Net Core 2.1中苦苦挣扎,this link may help

简而言之,如果您像这样使用AddDefaultIdentity

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

然后角色将无法使用,因为它们没有在DefaultIdentity中实现。

对我有用的是将其替换为:

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

此外,如果您在上述修复之前登录,请注销并再次登录,以便刷新身份声明。现在应该可以了。

答案 3 :(得分:1)

{。1}从.Net Core 2.1(也适用于3.1)开始,与调用相同:

  • AddDefaultIdentity
  • AddIdentity
  • AddDefaultUI

要添加角色功能,请转到AddDefaultTokenProviders下的Startup.cs,您可以像这样使用ConfigureServices

.AddRoles

仅此而已。像上面提到的那样再次注销并重新登录至关重要。

为了记录(为了测试),我尝试了services.AddDefaultIdentity<IdentityUser>() .AddRoles<IdentityRole>() //<-- This line .AddEntityFrameworkStores<ApplicationDbContext>();

IServiceCollection不包含对'AddIdentity'的定义...

services.AddIdentity(在“调试并显示页面”之前没有错误):

InvalidOperationException:未指定authenticationScheme,并且 找不到DefaultChallengeScheme。默认方案可以是 使用AddAuthentication(string defaultScheme)或 AddAuthentication(操作configureOptions)。

要使后两个功能正常工作,您可以做更多的工作,但是我要为services.AddIdentityCore发布的代码是使AddDefaultIdentity和其他角色功能在.NET Core中正常工作所需要的。到目前为止,只有2.1和3.1。

答案 4 :(得分:0)

我也发现了与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;
    }
};

答案 5 :(得分:0)

User.IsInRole()处理SignIn之后的下一个请求。在您的代码中,SignInUser.IsInRole()相同请求中执行。因此,要应用手动重定向,您可以将身份验证代码放入另一个操作中,然后从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()将起作用。

答案 6 :(得分:0)

就我而言,当用户已登录时,我已将该用户添加到数据库中的角色。注销并再次登录解决了该问题。