DB-First与ASP.NET Web API 2 + EF6的身份验证混淆

Vit*_*meo 14 c# asp.net entity-framework ef-database-first asp.net-web-api2

我需要为现有的MySQL数据库创建一个Web API C#应用程序.我已经设法使用Entity Framework 6将每个数据库表绑定到RESTful API (允许CRUD操作).

我想实现一个登录/注册系统(这样我以后就可以实现角色和权限,并限制某些API请求).

我必须使用的MySQL数据库有一个用户表(称为user),其中包含以下不言自明的列:

  • id
  • email
  • username
  • password_hash

似乎事实上的身份验证标准是ASP.Net Identity.我花了最后一小时试图弄清楚如何使Identity与现有的DB-First Entity Framework设置一起工作.

如果我尝试构造ApplicationUser存储user实例(MySQL数据库中的实体)的实例来检索用户数据,我会收到以下错误:

实体类型ApplicationUser不是当前上下文的模型的一部分.

我假设我需要在我的MySQL数据库中存储身份数据,但找不到任何有关如何执行此操作的资源.我已经尝试完全删除ApplicationUser类并使我的user实体类派生IdentityUser,但调用UserManager.CreateAsync导致LINQ to Entities转换错误.

如何在具有现有user实体的Web API 2应用程序中设置身份验证?

Fab*_*Luz 22

你说:

我想实现一个登录/注册系统(这样我以后就可以实现角色和权限,并限制某些API请求).

如何在具有现有用户实体的Web API 2应用程序中设置身份验证?

这无疑意味着,你不要需要ASP.NET身份.ASP.NET Identity是一种处理所有用户资料的技术.它实际上并没有"制造"认证机制.ASP.NET Identity使用OWIN身份验证机制,这是另一回事.

您正在寻找的不是"如何将ASP.NET Identity与我现有的Users表一起使用",而是"如何使用我现有的Users表配置OWIN身份验证"

要使用OWIN Auth,请执行以下步骤:

安装包:

Owin
Microsoft.AspNet.Cors
Microsoft.AspNet.WebApi.Client
Microsoft.AspNet.WebApi.Core
Microsoft.AspNet.WebApi.Owin
Microsoft.AspNet.WebApi.WebHost
Microsoft.Owin
Microsoft.Owin.Cors
Microsoft.Owin.Host.SystemWeb
Microsoft.Owin.Security
Microsoft.Owin.Security.OAuth
Run Code Online (Sandbox Code Playgroud)

Startup.cs在根文件夹中创建文件(示例):

确保正确配置[assembly:OwinStartup]

[assembly: OwinStartup(typeof(YourProject.Startup))]
namespace YourProject
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            var config = new HttpConfiguration();
            //other configurations

            ConfigureOAuth(app);
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.UseWebApi(config);
        }

        public void ConfigureOAuth(IAppBuilder app)
        {
            var oAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/api/security/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromHours(2),
                Provider = new AuthorizationServerProvider()
            };

            app.UseOAuthAuthorizationServer(oAuthServerOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        }
    }

    public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated();
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

            try
            {
                //retrieve your user from database. ex:
                var user = await userService.Authenticate(context.UserName, context.Password);

                var identity = new ClaimsIdentity(context.Options.AuthenticationType);

                identity.AddClaim(new Claim(ClaimTypes.Name, user.Name));
                identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));

                //roles example
                var rolesTechnicalNamesUser = new List<string>();

                if (user.Roles != null)
                {
                    rolesTechnicalNamesUser = user.Roles.Select(x => x.TechnicalName).ToList();

                    foreach (var role in user.Roles)
                        identity.AddClaim(new Claim(ClaimTypes.Role, role.TechnicalName));
                }

                var principal = new GenericPrincipal(identity, rolesTechnicalNamesUser.ToArray());

                Thread.CurrentPrincipal = principal;

                context.Validated(identity);
            }
            catch (Exception ex)
            {
                context.SetError("invalid_grant", "message");
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

使用该[Authorize]属性授权操作.

呼叫api/security/tokenGrantType,UserNamePassword得到的承载标记.像这样:

"grant_type=password&username=" + username + "&password=" password;
Run Code Online (Sandbox Code Playgroud)

HttpHeader Authorizationas中发送令牌Bearer "YOURTOKENHERE".像这样:

headers: { 'Authorization': 'Bearer ' + token }
Run Code Online (Sandbox Code Playgroud)

希望能帮助到你!

  • 是的,它是一个从数据库中检索用户的自定义类.是的,用户不必从任何东西继承,因为在上面的例子中,没有使用Identity. (2认同)

Sam*_*ari 7

由于您的数据库架构与默认值不兼容UserStore您必须实现自己的类UserStoreUserPasswordStore类,然后将它们注入UserManager.考虑这个简单的例子:

首先编写自定义用户类并实现IUser接口:

class User:IUser<int>
{
    public int ID {get;set;}
    public string Username{get;set;}
    public string Password_hash {get;set;}
    // some other properties 
}
Run Code Online (Sandbox Code Playgroud)

现在创建您的自定义UserStoreIUserPasswordStore类,如下所示:

public class MyUserStore : IUserStore<User>, IUserPasswordStore<User>
{
    private readonly MyDbContext _context;

    public MyUserStore(MyDbContext context)
    {
        _context=context;
    }

    public Task CreateAsync(AppUser user)
    {
        // implement your desired logic such as
        // _context.Users.Add(user);
    }

    public Task DeleteAsync(AppUser user)
    {
        // implement your desired logic
    }

    public Task<AppUser> FindByIdAsync(string userId)
    {
        // implement your desired logic
    }

    public Task<AppUser> FindByNameAsync(string userName)
    {
        // implement your desired logic
    }

    public Task UpdateAsync(AppUser user)
    {
        // implement your desired logic
    }

    public void Dispose()
    {
        // implement your desired logic
    }

    // Following 3 methods are needed for IUserPasswordStore
    public Task<string> GetPasswordHashAsync(AppUser user)
    {
        // something like this:
        return Task.FromResult(user.Password_hash);
    }

    public Task<bool> HasPasswordAsync(AppUser user)
    {
        return Task.FromResult(user.Password_hash != null);
    }

    public Task SetPasswordHashAsync(AppUser user, string passwordHash)
    {
        user.Password_hash = passwordHash;
        return Task.FromResult(0);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在您拥有自己的用户存储,只需将其注入用户管理器:

public class ApplicationUserManager: UserManager<User, int>
{
    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
         var manager = new ApplicationUserManager(new MyUserStore(context.Get<MyDbContext>()));
         // rest of code
    }
}
Run Code Online (Sandbox Code Playgroud)

同时请注意,您必须直接继承你的DB Context类从DbContext不是IdentityDbContext因为你已经实现了自己的用户存储.