DB-First与ASP.NET Web API 2 + EF6的身份validation混淆
我需要为现有的MySQL数据库创建一个Web API C#应用程序。 我已经设法使用Entity Framework 6将每个数据库表绑定到RESTful API (允许CRUD操作) 。
我想实现一个登录/注册系统(以便我将来可以实现角色和权限,并限制某些API请求) 。
我必须使用的MySQL数据库有一个用户表(称为user
) ,其中包含以下不言自明的列:
-
id
-
email
-
username
-
password_hash
似乎事实上的身份validation标准是ASP.Net Identity。 我花了最后一小时试图弄清楚如何使Identity与现有的DB-First Entity Framework设置一起工作。
如果我尝试构建存储user
实例(来自MySQL数据库的实体)的 ApplicationUser
实例来检索用户数据,我会收到以下错误:
实体类型ApplicationUser不是当前上下文的模型的一部分。
我假设我需要在我的MySQL数据库中存储身份数据,但找不到任何有关如何执行此操作的资源。 我已经尝试完全删除ApplicationUser
类并使我的user
实体类派生自IdentityUser
,但调用UserManager.CreateAsync
导致LINQ to Entities转换错误。
如何在具有现有user
实体的Web API 2应用程序中设置身份validation?
你说:
我想实现一个登录/注册系统(以便我将来可以实现角色和权限,并限制某些API请求)。
如何在具有现有用户实体的Web API 2应用程序中设置身份validation?
这绝对意味着您不需要ASP.NET身份。 ASP.NET Identity是一种处理所有用户资料的技术。 它实际上并没有“制造”认证机制。 ASP.NET Identity使用OWIN身份validation机制,这是另一回事。
您正在寻找的不是“如何将ASP.NET Identity与我现有的Users表一起使用” ,而是“如何使用我现有的Users表配置OWIN身份validation”
要使用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.Host.SystemWeb Microsoft.Owin.Security Microsoft.Owin.Security.OAuth
在根文件夹中创建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(); 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"); } } } }
使用[Authorize]
属性授权操作。
使用GrantType
, UserName
和Password
调用api/security/token
以获取承载令牌。 像这样:
"grant_type=password&username=" + username + "&password=" password;
在HttpHeader Authorization
中将令牌作为Bearer "YOURTOKENHERE"
。 像这样:
headers: { 'Authorization': 'Bearer ' + token }
希望能帮助到你!
由于您的数据库模式与默认的UserStore
不兼容您必须实现自己的UserStore
和UserPasswordStore
类,然后将它们注入UserManager
。 考虑这个简单的例子:
首先编写自定义用户类并实现IUser
接口:
class User:IUser { public int ID {get;set;} public string Username{get;set;} public string Password_hash {get;set;} // some other properties }
现在创建您的自定义UserStore
和IUserPasswordStore
类,如下所示:
public class MyUserStore : IUserStore, IUserPasswordStore { 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 FindByIdAsync(string userId) { // implement your desired logic } public Task 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 GetPasswordHashAsync(AppUser user) { // something like this: return Task.FromResult(user.Password_hash); } public Task 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); } }
现在您拥有自己的用户存储,只需将其注入用户管理器:
public class ApplicationUserManager: UserManager { public static ApplicationUserManager Create(IdentityFactoryOptions options, IOwinContext context) { var manager = new ApplicationUserManager(new MyUserStore(context.Get())); // rest of code } }
另请注意,您必须直接从DbContext
inheritance您的DB Context类, DbContext
不是IdentityDbContext
因为您已经实现了自己的用户存储。