新的ASP.NET MVC身份框架是否在没有实体框架和SQL Server的情况下工作?

Are*_*ref 35 sql-server entity-framework owin asp.net-mvc-5

我是ASP.NET MVC 5的新手,所以我试图尽可能地通过练习来学习它.

所以我正在考虑使用ASP.NET MVC的新OWIN实现来实现我的项目的身份验证和授权.也就是说,我正在以一种可以与各种类型的数据库一起工作的方式构建项目.

到目前为止,我使用了通用的ADO.NET元素(例如DbDataReaderetc),我拒绝使用任何ORM.所以我想知道我是否可以继续使用ASP.NET的新身份系统,或者如果我这样做,我将被绑定到Entity Framework和SQL Server吗?

And*_*tos 39

不那么简单.也没那么难.

您必须编写以下自定义实现:

  1. IUserStore<TUser>
  2. IUserPasswordStore<TUser>
  3. IUserTwoFactorStore<TUser>
  4. IUserClaimStore<TUser>
  5. IRoleStore<TRole>
  6. IUserSecurityStampStore<TUser, string>
  7. IUserRoleStore<TUser, string>
  8. UserManager<TUser>

然后创建自己的用户实现IUser<TKey>,例如:

public class MyUser : IUser<string>
{
    public string Id { get; set; }
    public string UserName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

最后,从NuGet中删除AspNet.Identity.EntityFramework,如果您没有在其他地方使用它,也会删除EntityFramework.

无论您的代码在哪里破解,都要重写它以使用您的自定义实现.

小费

创建一个实现1到7项的MyUserRepository.

然后,创建一个实现第8项的MyUserManager.

将它连接到默认的AspNet.Identity.EntityFramework类将很容易.

  • 一步步获取最新版本... https://markjohnson.io/articles/exorcising-entity-framework-from-asp-net-identity/ (2认同)

Tim*_*yer 16

为了捎带ALMMa所说的,当我在自己的自定义实现上工作时,我发现这篇文章非常宝贵:

ASP.NET身份的自定义存储提供程序概述

它不仅详细介绍了需要实现的接口,还详细介绍了如何实现它们,并提供了对实际MySQL实现的代码示例引用.


Nar*_*yal 6

您只需要以下列方式覆盖某些类,以使基本的基于角色的身份验证在没有实体框架和SQL的情况下工作.

public partial class Startup
{
    public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
    public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context, user manager and role manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Configure the application for OAuth based flow
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            // In production mode set AllowInsecureHttp = false
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);
    }
}
Run Code Online (Sandbox Code Playgroud)
public class ApplicationUser : IUser
{
    public ApplicationUser()
    {
        Id = Guid.NewGuid().ToString();
        Roles = new List<string>();
    }

    public virtual string Email { get; set; }
    public List<string> Roles { get; set; }
    public virtual string Password { get; set; }
    public DateTime CreatedTime { get; set; }

    public DateTime UpdatedTime { get; set; }

    public string Id { get; }
    public string UserName { get; set; }

    public virtual void AddRole(string role)
    {
        Roles.Add(role);
    }

    public virtual void RemoveRole(string role)
    {
        Roles.Remove(role);
    }
}
Run Code Online (Sandbox Code Playgroud)
public class ApplicationUserManager : UserManager<ApplicationUser>
    {
        public ApplicationUserManager(IUserStore<ApplicationUser> store)
            : base(store)
        {
        }

        public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options,
            IOwinContext context)
        {
            var manager =
                new ApplicationUserManager(
                    new UserStoreService<ApplicationUser>(context.Get<ApplicationDbContext>().Users));
            manager.PasswordHasher = new FusionPasswordHasher();

            // Configure validation logic for passwords
            manager.PasswordValidator = new PasswordValidator
            {
                RequiredLength = 6,
                RequireNonLetterOrDigit = false,
                RequireDigit = false,
                RequireLowercase = false,
                RequireUppercase = false
            };

            // Configure user lockout defaults
            manager.UserLockoutEnabledByDefault = true;
            manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
            manager.MaxFailedAccessAttemptsBeforeLockout = 5;

            var dataProtectionProvider = options.DataProtectionProvider;
            if (dataProtectionProvider != null)
                manager.UserTokenProvider =
                    new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
            return manager;
        }

        public virtual async Task<IdentityResult> AddUserToRolesAsync(string userId, IList<string> roles)
        {
            var userRoleStore = (IUserRoleStore<ApplicationUser, string>) Store;

            var user = await FindByIdAsync(userId).ConfigureAwait(false);
            if (user == null)
                throw new InvalidOperationException("Invalid user Id");

            var userRoles = await userRoleStore.GetRolesAsync(user).ConfigureAwait(false);
            // Add user to each role using UserRoleStore
            foreach (var role in roles.Where(role => !userRoles.Contains(role)))
                await userRoleStore.AddToRoleAsync(user, role).ConfigureAwait(false);

            // Call update once when all roles are added
            return await UpdateAsync(user).ConfigureAwait(false);
        }

        public virtual async Task<IdentityResult> RemoveUserFromRolesAsync(string userId, IList<string> roles)
        {
            var userRoleStore = (IUserRoleStore<ApplicationUser, string>) Store;

            var user = await FindByIdAsync(userId).ConfigureAwait(false);
            if (user == null)
                throw new InvalidOperationException("Invalid user Id");

            var userRoles = await userRoleStore.GetRolesAsync(user).ConfigureAwait(false);
            // Remove user to each role using UserRoleStore
            foreach (var role in roles.Where(userRoles.Contains))
                await userRoleStore.RemoveFromRoleAsync(user, role).ConfigureAwait(false);

            // Call update once when all roles are removed
            return await UpdateAsync(user).ConfigureAwait(false);
        }
    }
Run Code Online (Sandbox Code Playgroud)

如果您希望在一个简短的内容中读取所有用户并将其存储在内存中,而不是使用以下样式.我强烈建议您仅在登录时阅读用户,以便在"UserStoreService"类中添加逻辑.

public class ApplicationDbContext : IDisposable
{
    private ApplicationDbContext(IList<ApplicationUser> users)
    {
        Users = users;
    }

    public IList<ApplicationUser> Users { get; set; }

    public void Dispose()
    {
    }

    public static ApplicationDbContext Create()
    {
        //You can use any database and hook it here

        var users = new List<ApplicationUser>
        {
            new ApplicationUser
            {
                UserName = "a@a.com",
                Email = "a@a.com",
                Password = "test",
                Roles = new List<string> {"Admin", "Admin2"}
            },
            new ApplicationUser
            {
                UserName = "a@a2.com",
                Email = "a@a2.com",
                Password = "test2",
                Roles = new List<string> {"Admin"}
            }
        };

        return new ApplicationDbContext(users);
    }
}
Run Code Online (Sandbox Code Playgroud)
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

        var user = await userManager.FindAsync(context.UserName.ToLower(), context.Password);

        if (user == null)
        {
            context.SetError("invalid_grant", "The user name or password is incorrect.");
            return;
        }

        try
        {
            var oAuthIdentity = await userManager.CreateIdentityAsync(user, context.Options.AuthenticationType);
            var cookiesIdentity = await userManager.CreateIdentityAsync(user,
                CookieAuthenticationDefaults.AuthenticationType);
            var props = new AuthenticationProperties(new Dictionary<string, string>
            {
                {
                    "client_id", context.ClientId == null ? string.Empty : context.ClientId
                },
                {
                    "userName", context.UserName
                }
            });
            var ticket = new AuthenticationTicket(oAuthIdentity, props);
            context.Validated(ticket);
            context.Request.Context.Authentication.SignIn(cookiesIdentity);
        }
        catch (Exception ex)
        {
            Trace.TraceError("FUSION Error ::: " + ex.Message + ex.InnerException);
            Trace.TraceError(ex.Message);
        }
    }

    public override Task TokenEndpoint(OAuthTokenEndpointContext context)
    {
        foreach (var property in context.Properties.Dictionary)
            if (property.Value != null)
                context.AdditionalResponseParameters.Add(property.Key, property.Value);

        return Task.FromResult<object>(null);
    }

    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        // Resource owner password credentials does not provide a client ID.
        if (context.ClientId == null)
            context.Validated();

        return Task.FromResult<object>(null);
    }
}
Run Code Online (Sandbox Code Playgroud)
public class AppPasswordHasher : IPasswordHasher
{
    public string HashPassword(string password)
    {
        return password;
    }

    public PasswordVerificationResult VerifyHashedPassword
        (string hashedPassword, string providedPassword)
    {
        if (hashedPassword == HashPassword(providedPassword))
            return PasswordVerificationResult.Success;
        return PasswordVerificationResult.Failed;
    }
}
Run Code Online (Sandbox Code Playgroud)

像"FindByNameAsync"这样的方法; 您需要从db on demand/login读取用户的位置

public class UserStoreService<TUser> : IUserStore<TUser>,
    IUserPasswordStore<TUser>,
    IUserRoleStore<TUser>
    where TUser : ApplicationUser
{
    private readonly IList<TUser> _users;


    public UserStoreService(IList<TUser> users)
    {
        _users = users;
    }

    public virtual Task SetPasswordHashAsync(TUser user, string passwordHash)
    {
        user.Password = passwordHash;
        return Task.FromResult(0);
    }

    public virtual Task<string> GetPasswordHashAsync(TUser user)
    {
        return Task.FromResult(user.Password);
    }

    public virtual Task<bool> HasPasswordAsync(TUser user)
    {
        return Task.FromResult(user.Password != null);
    }

    public virtual Task AddToRoleAsync(TUser user, string roleName)
    {
        user.AddRole(roleName);
        return Task.FromResult(0);
    }

    public virtual Task RemoveFromRoleAsync(TUser user, string roleName)
    {
        user.RemoveRole(roleName);
        return Task.FromResult(0);
    }

    public virtual Task<IList<string>> GetRolesAsync(TUser user)
    {
        return Task.FromResult((IList<string>) user.Roles);
    }

    public virtual Task<bool> IsInRoleAsync(TUser user, string roleName)
    {
        return Task.FromResult(user.Roles.Contains(roleName));
    }

    public virtual void Dispose()
    {
    }

    public virtual Task CreateAsync(TUser user)
    {
        user.CreatedTime = DateTime.Now;
        user.UpdatedTime = DateTime.Now;
        _users.Add(user);
        return Task.FromResult(true);
    }

    public virtual Task UpdateAsync(TUser user)
    {
        // todo should add an optimistic concurrency check
        user.UpdatedTime = DateTime.Now;
        _users.Remove(user);
        _users.Add(user);
        return Task.FromResult(true);
    }

    public virtual Task DeleteAsync(TUser user)
    {
        return Task.FromResult(_users.Remove(user));
    }

    public virtual Task<TUser> FindByIdAsync(string userId)
    {
        return Task.FromResult(_users.FirstOrDefault(u => u.Id == userId));
    }

    public virtual Task<TUser> FindByNameAsync(string userName)
    {
        // todo exception on duplicates? or better to enforce unique index to ensure this
        return Task.FromResult(_users.FirstOrDefault(u => u.Email == userName));
    }
}
Run Code Online (Sandbox Code Playgroud)
[Authorize(Roles = "Admin")]
public class RolesController : ApiController
{
    public IEnumerable<string> Get()
    {
        return new[] {"value3", "value4"};
    }
}
Run Code Online (Sandbox Code Playgroud)

源代码(github)