簡體   English   中英

DB-First與ASP.NET Web API 2 + EF6的身份驗證混淆

[英]DB-First authentication confusion with ASP.NET Web API 2 + EF6

我需要為現有的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設置一起工作。

如果我嘗試構建存儲user實例(來自MySQL數據庫的實體)的 ApplicationUser實例來檢索用戶數據,我會收到以下錯誤:

實體類型ApplicationUser不是當前上下文的模型的一部分。

我假設我需要在我的MySQL數據庫中存儲身份數據,但找不到任何有關如何執行此操作的資源。 我已經嘗試完全刪除ApplicationUser類並使我的user實體類派生自IdentityUser ,但調用UserManager.CreateAsync導致LINQ to Entities轉換錯誤。

如何在具有現有user實體的Web API 2應用程序中設置身份驗證?

你說:

我想實現一個登錄/注冊系統(這樣我將來可以實現角色和權限,並限制某些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

在根文件夾中創建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");
            }
        }
    }
}

使用[Authorize]屬性授權操作。

使用GrantTypeUserNamePassword調用api/security/token以獲取承載令牌。 像這樣:

"grant_type=password&username=" + username + "&password=" password;

HttpHeader Authorization中將令牌作為Bearer "YOURTOKENHERE" 像這樣:

headers: { 'Authorization': 'Bearer ' + token }

希望能幫助到你!

由於您的數據庫架構與默認的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 
}

現在創建您的自定義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);
    }
}

現在您擁有自己的用戶存儲,只需將其注入用戶管理器:

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
    }
}

另請注意,您必須直接從DbContext繼承您的DB Context類, DbContext不是IdentityDbContext因為您已經實現了自己的用戶存儲。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM