我對這個解決方案是:摘要所有的東西
我身邊這讓通過抽象大部分身份的功能集成到自己的項目,該項目允許抽象的其他方便單元測試和重用項目。
我讀這篇文章
Persistence-Ignorant ASP.NET Identity with Patterns
然後我微調的思路,以適合我的需要後,計上心來。我基本上只是從asp.net.identity中爲我的自定義接口換取了所需的所有內容,這些接口或多或少地反映了框架提供的功能,但具有更容易的抽象而不是實現的優點。
IIdentityUser
/// <summary>
/// Minimal interface for a user with an id of type <seealso cref="System.String"/>
/// </summary>
public interface IIdentityUser : IIdentityUser<string> { }
/// <summary>
/// Minimal interface for a user
/// </summary>
public interface IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
TKey Id { get; set; }
string UserName { get; set; }
string Email { get; set; }
//...other code removed for brevity
}
IIdentityManager
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager : IIdentityManager<IIdentityUser> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser> : IIdentityManager<TUser, string>
where TUser : class, IIdentityUser<string> { }
/// <summary>
/// Exposes user related api which will automatically save changes to the UserStore
/// </summary>
public interface IIdentityManager<TUser, TKey> : IDisposable
where TUser : class, IIdentityUser<TKey>
where TKey : System.IEquatable<TKey> {
//...other code removed for brevity
}
IIdentityResult
/// <summary>
/// Represents the minimal result of an identity operation
/// </summary>
public interface IIdentityResult : System.Collections.Generic.IEnumerable<string> {
bool Succeeded { get; }
}
在我的身份管理器,它也住在自己的項目的默認實現,我只是包裹ApplicationManager
然後映射結果和功能之間的關係ñ我的類型和asp.net.identity類型。
public class DefaultUserManager : IIdentityManager {
private ApplicationUserManager innerManager;
public DefaultUserManager() {
this.innerManager = ApplicationUserManager.Instance;
}
//..other code removed for brevity
public async Task<IIdentityResult> ConfirmEmailAsync(string userId, string token) {
var result = await innerManager.ConfirmEmailAsync(userId, token);
return result.AsIIdentityResult();
}
//...other code removed for brevity
}
應用程序層只知道抽象,並在啓動時配置實現。我沒有更高層的using Microsoft.AspNet.Identity
,因爲他們都使用本地抽象。
該層可以是這樣的:
- API - 定義了服務(包括身份抽象接口)
- 域接口 - 商店POCO模型代表業務領域
- 業務 - 存儲邏輯對於域對象的交互,以及消費服務
- 服務 - 實施服務,包括實體框架,結構圖,爲域對象
- 身份 - 實施Microsoft.AspNet.Identity特殊服務,包括Microsoft.AspNet.Identity.EntityFramework;和OWIN配置
- 應用 - 在這種情況下,MVC應用程序。
在MVC應用程序層的AccountController
因此只需要
using MyNamespace.Identity.Abstractions
public partial class AccountController : Controller {
private readonly IIdentityManager userManager;
public AccountController(IIdentityManager userManager) {
this.userManager = userManager;
}
//...other code removed for brevity
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Signin(LoginViewModel model, string returnUrl) {
if (ModelState.IsValid) {
// authenticate user
var user = await userManager.FindAsync(model.UserName, model.Password);
if (user != null) {
//...code removed for brevity
} else {
// login failed
setFailedLoginIncrementalDelay();
ModelState.AddModelError("", "Invalid user name or password provided.");
}
}
//TODO: Audit failed login
// If we got this far, something failed, redisplay form
return View(model);
}
}
這裏假設你使用的是一些DI框架。只有在IoC的配置中,任何提到的實現身份的層完全將其從需要使用身份的人身上抽象出來。
//NOTE: This is custom code.
protected override void ConfigureDependencies(IContainerBuilder builder) {
if (!builder.HasHandler(typeof(IIdentityManager))) {
builder.PerRequest<IIdentityManager, DefaultUserManager>();
}
}
感謝您的詳細答覆!它看起來會直接下降。你的架構與我的基本相同。我正在使用DI(簡單注入器),因此將用戶管理器注入控制器應該沒問題。 – AndrewP