首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >ASP.NET 5身份-自定义SignInManager

ASP.NET 5身份-自定义SignInManager
EN

Stack Overflow用户
提问于 2015-07-07 22:33:38
回答 3查看 26.5K关注 0票数 31

我有一个MVC6项目(vNext),我正在使用ASP.NET标识。在我的例子中,我不想使用使用EF (SignInManager,UserManager,UserStore)的内置东西。我有一个外部数据库,我只想查找用户名/密码并返回一个有效的cookie。所以我开始编写自己的类。

代码语言:javascript
复制
public class MyUser
{
    public string Id { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
    public string PasswordHash { get; set; }
}

public class MyUserStore : IUserStore<MyUser>, IUserPasswordStore<MyUser>
{
    ...
}

MyUserStore类中,我使用硬编码的用户列表作为我的存储(仅用于测试目的)。我重写了一些方法,只是为了从硬编码的存储中返回数据。

代码语言:javascript
复制
public class MyUserManager : UserManager<MyUser>
{
    public MyUserManager(
        IUserStore<MyUser> store,
        IOptions<IdentityOptions> optionsAccessor,
        IPasswordHasher<MyUser> passwordHasher,
        IEnumerable<IUserValidator<MyUser>> userValidators,
        IEnumerable<IPasswordValidator<MyUser>> passwordValidators,
        ILookupNormalizer keyNormalizer,
        IdentityErrorDescriber errors,
        IEnumerable<IUserTokenProvider<MyUser>> tokenProviders,
        ILoggerFactory logger,
        IHttpContextAccessor contextAccessor) :
        base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, tokenProviders, logger, contextAccessor)
    {
    }
}

这里,我将CheckPasswordAsyncVerifyPasswordAsync方法分别返回truePasswordVerificationResult.Success,以便于测试。

代码语言:javascript
复制
public class MyClaimsPrincipleFactory : IUserClaimsPrincipalFactory<MyUser>
{
    public Task<ClaimsPrincipal> CreateAsync(MyUser user)
    {
        return Task.Factory.StartNew(() =>
        {
            var identity = new ClaimsIdentity();
            identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
            var principle = new ClaimsPrincipal(identity);

            return principle;
        });
    }
}

public class MySignInManager : SignInManager<MyUser>
{
    public MySignInManager(MyUserManager userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory<MyUser> claimsFactory, IOptions<IdentityOptions> optionsAccessor = null, ILoggerFactory logger = null)
            : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger)
    {
    }

    public override Task<SignInResult> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
    {
        // here goes the external username and password look up

        if (userName.ToLower() == "username" && password.ToLower() == "password")
        {
            return base.PasswordSignInAsync(userName, password, isPersistent, shouldLockout);
        }
        else
        {
            return Task.FromResult(SignInResult.Failed);
        }
    }
}

并且所有内容都在Startup类中连接起来,如下所示:

代码语言:javascript
复制
services.AddIdentity<MyUser, MyRole>()
            .AddUserStore<MyUserStore>()
            .AddUserManager<MyUserManager>()
            .AddDefaultTokenProviders();

而且因为我没有设法在Startup代码中创建MySignInManager对象以便将其添加到DI中(以便稍后在控制器和视图中注入),所以我在MyAccountController中创建它。

代码语言:javascript
复制
public MyAccountController(IHttpContextAccessor httpContextAccessor, UserManager<MyUser> userManager, IOptions<IdentityOptions> optionsAccessor, ILoggerFactory logger)
{
    SignInManager = new MySignInManager(userManager as MyUserManager, httpContextAccessor, new MyClaimsPrincipleFactory(), optionsAccessor, logger);
}

MyAccount控制器中的MyLogin操作中,我调用了PasswordSignInAsync,可以看到我正在(从MyClaimsPrincipleFactory)获取包含编码声明的cookie。当我尝试调用带有cookie的其他操作时,我可以看到AuthorizeAttribute在请求标头中,但我是未经授权的(更准确地说,因为我没有从visual studio示例模板中删除内置的默认ASP.NET身份验证,所以我被重定向到帐户/登录)。

这是自定义ASP.NET身份的正确方式吗?我在这里缺少什么?

EN

回答 3

Stack Overflow用户

发布于 2016-01-27 23:05:02

我在尝试使用自定义SignInManager时也遇到了问题,结果证明实现起来真的很容易。

Startup.cs中,在默认实现services.Identity之后

代码语言:javascript
复制
services.AddIdentity<ApplicationUser, IdentityRole>()
    .AddEntityFrameworkStores<ApplicationDbContext>()
    .AddDefaultTokenProviders();

您只需要向内置DI注入以下内容:

代码语言:javascript
复制
services.AddScoped<SignInManager<MyApplicationUser>, MySignInManager>();

默认的SignInManager会被自定义的The覆盖。

票数 10
EN

Stack Overflow用户

发布于 2015-07-07 23:50:33

在我的项目中,我在不使用EF的情况下实现了identity。我认为你可能实现了比你需要的更多。UserManager和SignInManager与EF无关。如果你愿意,你可以实现这些,但你不需要仅仅为了摆脱EF。如果您需要验证硬编码的密码以进行测试,那么您只需要实现UserStore和RoleStore,也许还需要实现PasswordHasher。

代码语言:javascript
复制
services.TryAdd(ServiceDescriptor.Scoped<IUserStore<SiteUser>, UserStore<SiteUser>>());
services.TryAdd(ServiceDescriptor.Scoped<IUserPasswordStore<SiteUser>, UserStore<SiteUser>>());
services.TryAdd(ServiceDescriptor.Scoped<IUserEmailStore<SiteUser>, UserStore<SiteUser>>());
services.TryAdd(ServiceDescriptor.Scoped<IUserLoginStore<SiteUser>, UserStore<SiteUser>>());
services.TryAdd(ServiceDescriptor.Scoped<IUserRoleStore<SiteUser>, UserStore<SiteUser>>());
services.TryAdd(ServiceDescriptor.Scoped<IUserClaimStore<SiteUser>, UserStore<SiteUser>>());
services.TryAdd(ServiceDescriptor.Scoped<IUserPhoneNumberStore<SiteUser>, UserStore<SiteUser>>());
services.TryAdd(ServiceDescriptor.Scoped<IUserLockoutStore<SiteUser>, UserStore<SiteUser>>());
services.TryAdd(ServiceDescriptor.Scoped<IUserTwoFactorStore<SiteUser>, UserStore<SiteUser>>());
services.TryAdd(ServiceDescriptor.Scoped<IRoleStore<SiteRole>, RoleStore<SiteRole>>());
services.TryAdd(ServiceDescriptor.Scoped<IUserClaimsPrincipalFactory<SiteUser>, SiteUserClaimsPrincipalFactory<SiteUser, SiteRole>>());
services.TryAdd(ServiceDescriptor.Transient<IPasswordHasher<SiteUser>, SitePasswordHasher<SiteUser>>());
services.AddIdentity<SiteUser, SiteRole>();

上面显示了我为绕过实体框架而实现的项目,例如,我的AccountController为

代码语言:javascript
复制
    UserManager<SiteUser> userManager,
            SignInManager<SiteUser> signInManager

哪些是我不必使用DI服务进行设置的标准identity UserManager和SignInManager,它们是通过下面的行为我注册的:

代码语言:javascript
复制
services.AddIdentity<SiteUser, SiteRole>();

你可以使用see the code for that extension method here。它是身份的一部分,而不是EFIdentity的一部分。您可以看到,我还实现了IUserClaimsPrincipalFactory。我实现它的唯一原因是添加一些自定义声明,我不需要这样做来摆脱EF。

票数 6
EN

Stack Overflow用户

发布于 2017-12-19 02:48:49

您可以通过在Startup.ConfigureServices方法中使用IdentityBuilder.AddSignInManager方法来注册自定义SignInManager以进行依赖注入,如下所示:

代码语言:javascript
复制
services.AddIdentity<MyUser, IdentityRole<int>>()
    .AddUserStore<UserStore<MyUser, IdentityRole<int>, SqlContext, int>>()
    .AddRoleStore<RoleStore<IdentityRole<int>, SqlContext, int>>()
    .AddSignInManager<SignInManager<MyUser>>()
    .AddDefaultTokenProviders();

您实现的SignInManager没有理由不能以同样的方式为DI注册。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31271600

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档