Идентификация.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
Я решил эту проблему, создав представление со всеми необходимыми столбцами (включая роли) и добавив его в контекст.