我对这个解决方案是:摘要所有的东西
我身边这让通过抽象大部分身份的功能集成到自己的项目,该项目允许抽象的其他方便单元测试和重用项目。
我读这篇文章
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