Идентификация.NET Core 2.1 позволяет всем пользователям выполнять связанные роли

Я пытаюсь вытащить всех своих пользователей Identity и связанных с ними ролей для страницы администрирования управления пользователями. Я думал, что это будет достаточно легко, но, видимо, нет. Я пробовал выполнить следующее решение: qaru.site/info/13605295/... но до сих пор он не разработан.

Вот что я имею до сих пор:

ApplicationUser:

public class ApplicationUser : IdentityUser
{
    public List<IdentityUserRole<string>> Roles { get; set; }
}

DbContext

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

Идентификационный код запуска

services.AddIdentity<ApplicationUser, IdentityRole>(options => options.Stores.MaxLengthForKeys = 128)
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

Страница Razor, где я хочу отобразить список:

public class IndexModel : PageModel
{
    private readonly UserManager<ApplicationUser> userManager;

    public IndexModel(UserManager<ApplicationUser> userManager)
    {
        this.userManager = userManager;
    }

    public IEnumerable<ApplicationUser> Users { get; set; }

    public void OnGetAsync()
    {
        this.Users = userManager.Users.Include(u => u.Roles).ToList();
    }
}

Я получаю следующую ошибку при вызове userManager.Users.Include(u => u.Roles).ToList(); :

MySql.Data.MySqlClient.MySqlException: 'Неизвестный столбец' u.Roles.ApplicationUserId 'в' списке полей ''

Ответ 1

Теперь я реализовал следующее решение.

Как отмечалось в комментариях CodeNotFound, у IdentityUser было свойство Roles. Это больше не относится к .NET Core. Этот комментарий/проблема на GitHub, кажется, является текущим решением для .Net Core. Я попытался реализовать это с помощью следующего кода:

ApplicationUser

public class ApplicationUser : IdentityUser
{
    public ICollection<ApplicationUserRole> UserRoles { get; set; }
}

ApplicationUserRole

public class ApplicationUserRole : IdentityUserRole<string>
{
    public virtual ApplicationUser User { get; set; }
    public virtual ApplicationRole Role { get; set; }
}

ApplicationRole

public class ApplicationRole : IdentityRole
{
    public ICollection<ApplicationUserRole> UserRoles { get; set; }
}

DbContext

public class ApplicationDbContext
    : IdentityDbContext<ApplicationUser, ApplicationRole, string, IdentityUserClaim<string>,
    ApplicationUserRole, IdentityUserLogin<string>,
    IdentityRoleClaim<string>, IdentityUserToken<string>>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

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

        builder.Entity<ApplicationUserRole>(userRole =>
        {
            userRole.HasKey(ur => new { ur.UserId, ur.RoleId });

            userRole.HasOne(ur => ur.Role)
                .WithMany(r => r.UserRoles)
                .HasForeignKey(ur => ur.RoleId)
                .IsRequired();

            userRole.HasOne(ur => ur.User)
                .WithMany(r => r.UserRoles)
                .HasForeignKey(ur => ur.UserId)
                .IsRequired();
        });
    }
}

Запускать

services.AddIdentity<ApplicationUser, ApplicationRole>(options => options.Stores.MaxLengthForKeys = 128)
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();

Наконец, убедитесь, что когда вы используете его, вы охотно загружаете UserRoles пользователя, а затем UserRole Role, например, так:

this.Users = userManager.Users.Include(u => u.UserRoles).ThenInclude(ur => ur.Role).ToList();

У меня была проблема, когда свойство Role каждого UserRole было нулевым, и это было решено добавлением части .ThenInclude(ur => ur.Role).

Документ Microsoft о многоуровневой активной загрузке: https://docs.microsoft.com/en-us/ef/core/querying/related-data#incключ-multiple-levels

ASP Core 2.2 обновление

Присущий IdentityUserRole<Guid> не строка Вам также может понадобиться удалить код из ModelBuilder для работы миграции.

Ответ 2

циклически просматривает список пользователей и получает роли пользователей, вызывая функцию _userManager.GetRolesAsync(user) и просматривая роли пользователей и разделяя роли с помощью "," в одной строковой переменной

[HttpPost]
    public async Task<IActionResult> OnPostGetPagination()
    {


        var users = await _userManager.Users.ToListAsync();
        InputModel inputModel = new InputModel();
        foreach (var v in users)
        {
            inputModel = new InputModel();
            var roles = await _userManager.GetRolesAsync(v);
            inputModel.Email = v.UserName;
            inputModel.role = "";
            foreach (var r in roles)
            {
                if (!inputModel.role.Contains(","))
                {
                    inputModel.role = r;
                }
                else
                {
                    inputModel.role = "," + r;
                }
            }
            Input2.Add(inputModel);
        }


    }

удачи

Ответ 3

Ссылка на комментарий

Первый - это код для получения данных.

 public async Task<IEnumerable<AccountViewModel>> GetUserList()
        {
            var userList = await (from user in _context.Users
                                  select new
                                  {
                                      UserId = user.Id,
                                      Username = user.UserName,
                                      user.Email,
                                      user.EmailConfirmed,
                                      RoleNames = (from userRole in user.Roles //[AspNetUserRoles]
                                                   join role in _context.Roles //[AspNetRoles]//
                                                   on userRole.RoleId
                                                   equals role.Id
                                                   select role.Name).ToList()
                                  }).ToListAsync();

            var userListVm = userList.Select(p => new AccountViewModel
            {
                UserId = p.UserId,
                UserName = p.Username,
                Email = p.Email,
                Roles = string.Join(",", p.RoleNames),
                EmailConfirmed = p.EmailConfirmed.ToString()
            });

            return userListVm;
        }

В ASP.Net core 2.1 мы должны настроить ApplicationRole таким образом, чтобы получить роли пользователей. Вам необходимо определить данные, которые вы хотите явно использовать для использования пользователем.

public class ApplicationRole : IdentityRole
    {
        public virtual ICollection<IdentityUserRole<string>> Users { get; set; }

        public virtual ICollection<IdentityRoleClaim<string>> Claims { get; set; }
    }

в заключение

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

            foreach (var relationship in modelBuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
            {
                relationship.DeleteBehavior = DeleteBehavior.Restrict;
            }

            modelBuilder.Entity<User>().HasMany(u => u.Claims).WithOne().HasForeignKey(c => c.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);
            modelBuilder.Entity<User>().HasMany(u => u.Roles).WithOne().HasForeignKey(r => r.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);

            modelBuilder.Entity<ApplicationRole>().HasMany(r => r.Claims).WithOne().HasForeignKey(c => c.RoleId).IsRequired().OnDelete(DeleteBehavior.Cascade);
            modelBuilder.Entity<ApplicationRole>().HasMany(r => r.Users).WithOne().HasForeignKey(r => r.RoleId).IsRequired().OnDelete(DeleteBehavior.Cascade);

            modelBuilder.EnableAutoHistory(null);
        }

Результатом будет имя пользователя и роли пользователя. Если пользователь имеет более 1 роли, данные будут отображаться, как этот Admin, Editor и т.д....

Полный код можно найти здесь здесь здесь и здесь Надеюсь, что эта помощь.

Ответ 4

Так как это лучший результат поиска Google; В настоящее время вы можете просто присоединиться к базе данных UserRoles (если ваш контекст базы данных наследуется от IdentityDbContext).

Например, внешнее соединение таблицы ролей с любыми пользовательскими ролями, а затем создание нашего manageUserModel (сокращенная информация о классе applicationUser для нашего API):

var employees = (from bb in _appContext.Users
            join roleIds in _appContext.UserRoles on bb.Id equals roleIds.UserId
            join role in _appContext.Roles on roleIds.RoleId equals role.Id into roles
            orderby bb.LastName, bb.FirstName
            where roles !=null && roles.Any(e => e.Name == Permissions.RoleNames.Administrator || e.Name == Permissions.RoleNames.Employee)
            select ManageUserModel.FromInfo(bb, roles)).ToList();

public static ManageUserModel FromInfo(ApplicationUser info, IEnumerable<UserRole> roles)
    {
        var ret= FromInfo(info);
        ret.Roles = roles.Select(e => new SimpleEntityString() {Id=e.Id, Text=e.Name}).ToList();
        return ret;
    }

Это также демонстрирует предложение where с использованием любой информации о роли (вышеизложенное выбирает только пользователей в наших ролях Admin и Employee).

Примечание: это внутреннее объединяет IdentityUserRole, поэтому будут возвращены только пользователи с ролью, если вы хотите, чтобы все пользователи просто добавили "into identifRoles" в конец строки присоединения roleIds... и соответствующим образом изменили остальные условия.

Ответ 5

Работал отлично. Я использую целочисленные ключи, поэтому я заменил "строку" на "int"

ApplicationRole : IdentityRole<int>
ApplicationUserRole : IdentityUserRole<int>
ApplicationUser : IdentityUser<int>

ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int, 
IdentityUserClaim<int>,
ApplicationUserRole, IdentityUserLogin<int>, IdentityRoleClaim<int>, 
IdentityUserToken<int>>

Linq: RoleId = (из a в m.UserRoles выберите a.Role.Id).FirstOrDefault(),

Ответ 6

Принятый ответ потребовал настройки идентификатора по расширению, что без этого отключит использование roleManager и userManager. При настройке ASP.NET Core Identity больше не следует использовать AddEntityFrameworkStores. Потому что он переопределит все ваши предыдущие настройки и настройки по умолчанию для служб идентификации. Сначала вам нужно создать новые сервисы со следующими сигнатурами: почему это нарушает ограничение параметра типа 'TUser'?

Без расширения, используя userManager и roleManager:

namespace identityDemo.Controllers
{
    public class UserManagementController : Controller
    {
        private readonly ApplicationDbContext _context;
        private readonly RoleManager<IdentityRole> _roleManager;
        private readonly UserManager<IdentityUser> _userManager;

            public UserManagementController(ApplicationDbContext context, 
UserManager<IdentityUser> userManager, RoleManager<IdentityRole> roleManager)
        {
            _context = context;
            _roleManager = roleManager; 
            _userManager = userManager; 
        }

        // GET: ApplicationUserRoles
        public async Task<IActionResult> GetApplicationUsersAndRoles()
        {
            return View(new UserMv(
                (from user in await _userManager.Users.ToListAsync()
                 select new UserMv(user, GetUserRoles(user).Result)).ToList()));
        }

        private async Task<List<string>> GetUserRoles(IdentityUser user)
        {
            return new List<string>(await _userManager.GetRolesAsync(user));
        }
}

С простым конструктором для отображения в DTO:

namespace IdentityDemo.Models.ModelView
{
    public class UserMv
    {
public UserMv(IdentityUser aus, List<string> userRoles)
        {
            UserId = aus.Id;
            UserName = aus.UserName;
            RolesHeld = userRoles; 
            Email = aus.Email;
            EmailConfirmed = aus.EmailConfirmed;
            LockoutEnabled = aus.LockoutEnabled;
            AccessFailedCount = aus.AccessFailedCount;
        }
}

и запуск.

services.AddDefaultIdentity<IdentityUser>()
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();

Ответ 7

Мне нужно было отобразить все роли, которые пользователь имеет в представлении, вместо решений, представленных здесь уже, я пошел с этой быстрой и грязной вещью:

@foreach(var user in Model.Users)
        {
        <tr>
            <td>@user.Email</td>
            <td>@String.Join(", ", @Model._userManager.GetRolesAsync(user).GetAwaiter().GetResult().ToArray())</td>
        </tr>
        }

_userManager должен быть публичным, чтобы это работало. и пользователь просто экземпляр IdentityUser.

Ответ 8

Я решил эту проблему, создав представление со всеми необходимыми столбцами (включая роли) и добавив его в контекст.