Так, проведя около дня или поэтому чтение и чтение, я закончил строить свою собственную реализацию Подлинность. Сначала я сделал свой существующий объект Employee
и расширил его, чтобы наследовать от IUser<int>
. IUser<int>
- это интерфейс, который является частью Identity 2.0 (в настоящее время в альфа), который позволяет настроить тип первичного ключа на что-то, отличное от string
, по умолчанию в 1.0. Из-за того, как я храню данные, моя реализация была действительно конкретной. Например, Employee
может иметь несколько связанных с ним объектов Email
, и для моего приложения я хотел использовать электронные письма в качестве имен пользователей. Таким образом, я просто установить UserName
свойства возвращаться в Employee
«сек работы по электронной почте:
public string UserName {
get {
if (this.WorkEmail != null) {
return this.WorkEmail.Address;
}
return null;
}
set {
/// This property is non-settable.
}
}
примечания стороны, так как я не собираюсь использовать сеттер для свойства, есть уборщик способ obsoleting его кроме простого оставления его пустым?
Продолжая, я также добавил PasswordHash
. Я добавил свой собственный объект Role
, наследующий от IRole<int>
. Наконец, объекты Employee
и Role
имеют ICollection<T>
, связывающие друг с другом. Еще одно замечание: реализация Identity Framework Identity вручную создает таблицу сопоставления UserRoles
вместо того, чтобы использовать свои собственные возможности настройки, и я не могу понять, почему это объясняется.Созданный UserRole
получает передается в *Store
, который он реализует, но на самом деле он не делает ничего особенного, кроме как действовать как ссылка. В моей реализации я просто использовал уже установленную ссылку, которая, конечно, создает таблицу сопоставления в базе данных, но не бесцельно раскрывается в приложении. Мне просто любопытно.
Переходим снова, с моими сконфигурированных объектов я пошел вперед и реализовать мои собственные IUserStore
и IRoleStore
классы творчески называемые EmployeeStore
и RoleStore
:
public class EmployeeStore : IQueryableUserStore<Employee, int>, IUserStore<Employee, int>, IUserPasswordStore<Employee, int>, IUserRoleStore<Employee, int>, IDisposable {
private bool Disposed;
private IDatabaseRepository<Role> RolesRepository { get; set; }
private IDatabaseRepository<Employee> EmployeesRepository { get; set; }
public EmployeeStore(
IDatabaseRepository<Role> rolesRepository,
IDatabaseRepository<Employee> employeesRepository) {
this.RolesRepository = rolesRepository;
this.EmployeesRepository = employeesRepository;
}
#region IQueryableUserStore Members
public IQueryable<Employee> Users {
get {
return this.EmployeesRepository.Set;
}
}
#endregion
#region IUserStore Members
public async Task CreateAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
await this.EmployeesRepository.AddAndCommitAsync(employee);
}
public async Task DeleteAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
await this.EmployeesRepository.RemoveAndCommitAsync(employee);
}
public Task<Employee> FindByIdAsync(
int employeeId) {
this.ThrowIfDisposed();
return Task.FromResult<Employee>(this.EmployeesRepository.FindSingleOrDefault(
u =>
(u.Id == employeeId)));
}
public Task<Employee> FindByNameAsync(
string userName) {
this.ThrowIfDisposed();
return Task.FromResult<Employee>(this.EmployeesRepository.FindSingleOrDefault(
e =>
(e.UserName == userName)));
}
public async Task UpdateAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
await this.EmployeesRepository.CommitAsync();
}
#endregion
#region IDisposable Members
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(
bool disposing) {
this.Disposed = true;
}
private void ThrowIfDisposed() {
if (this.Disposed) {
throw new ObjectDisposedException(base.GetType().Name);
}
}
#endregion
#region IUserPasswordStore Members
public Task<string> GetPasswordHashAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
return Task.FromResult<string>(employee.PasswordHash);
}
public Task<bool> HasPasswordAsync(
Employee employee) {
return Task.FromResult<bool>(!String.IsNullOrEmpty(employee.PasswordHash));
}
public Task SetPasswordHashAsync(
Employee employee,
string passwordHash) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
employee.PasswordHash = passwordHash;
return Task.FromResult<int>(0);
}
#endregion
#region IUserRoleStore Members
public Task AddToRoleAsync(
Employee employee,
string roleName) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
if (String.IsNullOrEmpty(roleName)) {
throw new ArgumentNullException("roleName");
}
Role role = this.RolesRepository.FindSingleOrDefault(
r =>
(r.Name == roleName));
if (role == null) {
throw new InvalidOperationException("Role not found");
}
employee.Roles.Add(role);
return Task.FromResult<int>(0);
}
public Task<IList<string>> GetRolesAsync(
Employee employee) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
return Task.FromResult<IList<string>>(employee.Roles.Select(
r =>
r.Name).ToList());
}
public Task<bool> IsInRoleAsync(
Employee employee,
string roleName) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
if (String.IsNullOrEmpty(roleName)) {
throw new ArgumentNullException("roleName");
}
return Task.FromResult<bool>(employee.Roles.Any(
r =>
(r.Name == roleName)));
}
public Task RemoveFromRoleAsync(
Employee employee,
string roleName) {
this.ThrowIfDisposed();
if (employee == null) {
throw new ArgumentNullException("employee");
}
if (String.IsNullOrEmpty(roleName)) {
throw new ArgumentNullException("roleName");
}
Role role = this.RolesRepository.FindSingleOrDefault(
r =>
(r.Name == roleName));
if (role == null) {
throw new InvalidOperationException("Role is null");
}
employee.Roles.Remove(role);
return Task.FromResult<int>(0);
}
#endregion
}
RoleStore
:
public class RoleStore : IQueryableRoleStore<Role, int>, IRoleStore<Role, int>, IDisposable {
private bool Disposed;
private IDatabaseRepository<Role> RolesRepository { get; set; }
public RoleStore(
IDatabaseRepository<Role> rolesRepository) {
this.RolesRepository = rolesRepository;
}
#region IQueryableRoleStore Members
public IQueryable<Role> Roles {
get {
return this.RolesRepository.Set;
}
}
#endregion
#region IRoleStore Members
public async Task CreateAsync(
Role role) {
this.ThrowIfDisposed();
if (role == null) {
throw new ArgumentNullException("role");
}
await this.RolesRepository.AddAndCommitAsync(role);
}
public async Task DeleteAsync(
Role role) {
this.ThrowIfDisposed();
if (role == null) {
throw new ArgumentNullException("role");
}
await this.RolesRepository.RemoveAndCommitAsync(role);
}
public Task<Role> FindByIdAsync(
int roleId) {
this.ThrowIfDisposed();
return Task.FromResult<Role>(this.RolesRepository.FindSingleOrDefault(
r =>
(r.Id == roleId)));
}
public Task<Role> FindByNameAsync(
string roleName) {
this.ThrowIfDisposed();
return Task.FromResult<Role>(this.RolesRepository.FindSingleOrDefault(
r =>
(r.Name == roleName)));
}
public async Task UpdateAsync(
Role role) {
this.ThrowIfDisposed();
if (role == null) {
throw new ArgumentNullException("role");
}
await this.RolesRepository.CommitAsync();
}
#endregion
#region IDisposable Members
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(
bool disposing) {
this.Disposed = true;
}
private void ThrowIfDisposed() {
if (this.Disposed) {
throw new ObjectDisposedException(base.GetType().Name);
}
}
#endregion
}
Теперь, что я заметил, было то, что реализация Entity Framework создавала то, что выглядело как мини-репозиторий. Поскольку мой проект уже использовал мою собственную репозиториальную реализацию, я решил использовать ее вместо этого. Посмотрим, как это получится ...
Теперь все это работает и на удивление не сбой вообще, или, по крайней мере, еще нет. При этом у меня есть все эти замечательные реализации Identity, но я не могу понять, как использовать их в моем приложении MVC. Так как это выходит за рамки этого вопроса, я пойду вперед и открою новый, который обращается к этому вопросу.
Я оставляю это как ответ на вопрос, если кто-то другой столкнется с этим в будущем. Конечно, если кто-нибудь увидит ошибку в коде, который я опубликовал, сообщите мне.
не мог бы вы просто переопределить свойство «пароль» в производном класс? – GFoley83
@ GFoley83 - Какова была бы цель переопределить свойство пароля? –
Ничего особенного, просто семантика действительно. Обычно я предпочитаю, чтобы мои производные классы содержали все свойства, когда базовый класс содержится в другой DLL сборки/третьей стороны, поскольку не всегда понятно/интуитивно понятно, какие свойства вы наследуете. – GFoley83