13

既存のMySQLデータベース用のWeb API C#アプリケーションを作成する必要があります。私はEntity Framework 6を​​使用して、すべてのデータベーステーブルをRESTful API (CRUD操作を許可する)にバインドしましたDB-First認証のASP.NET Web API 2 + EF6との混乱

私は、ログイン/登録システムを実装したいと思います(将来的に役割と権限を実装し、特定のAPIリクエストを制限できるように)

  • id
  • email
  • username
  • password_hash

    私が使用する必要がMySQLデータベースには、次の自明の列があります(userと呼ばれる)ユーザーのためのテーブルを持っています

認証の事実上の標準はASP.Net IDであるようです。私はアイデンティティを既存のDB-First Entity Frameworkセットアップと連携させる方法を見つけようと、最後の1時間を費やしました。

私は、ユーザーのデータを取得するためにuserインスタンス(MySQLデータベースからのエンティティ)を格納ApplicationUserインスタンスを構築しようとすると、私は次のエラーを取得する:

The entity type ApplicationUser is not part of the model for the current context.

私は私がアイデンティティデータを格納する必要があると仮定私のMySQLデータベースは、どのようにそれを行うにはリソースを見つけることができませんでした。 ApplicationUserクラスを完全に削除し、エンティティクラスをIdentityUserから派生させましたが、UserManager.CreateAsyncを呼び出すと、LINQ to Entitiesの変換エラーが発生しました。

既存のuserエンティティを持つWeb API 2アプリケーションで認証を設定するにはどうすればよいですか?あなたのDBスキーマ以来

答えて

19

あなたは言う:

I want to implement a login/registration system (so that I can implement roles and permissions in the future, and restrict certain API requests).

How do I setup authentication in a Web API 2 application, having an existing user entity?

それは間違いなくあなたではない必要ASP.NETアイデンティティをDO ことを意味します。 ASP.NET IDは、すべてのユーザーの操作を処理するテクノロジです。実際には、認証メカニズムを「作る」わけではありません。 ASP.NET IDはOWIN認証メカニズムを使用します。これは別のものです。

何を探してるんですが、「私の既存のユーザー表とASP.NETのアイデンティティを使用する方法」ないがが、OWINを使用するには

を「私の既存のユーザーテーブルを使用してOWIN認証を設定する方法」認証次の手順を実行します。

は、パッケージをインストールします。

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 

は、ルートフォルダ(examp内部Startup.csファイルを作成します。ル):

[アセンブリ:OwinStartup]があることを確認して正しく行動を承認する[Authorize]属性を使用し

[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"); 
      } 
     } 
    } 
} 

を設定されています。

GrantTypeUserNamePasswordとを呼び出して、ベアラトークンを取得します。このように:

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

Bearer "YOURTOKENHERE"としてHttpHeader Authorization内のトークンを送信します。このように:

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

希望します。

+0

ありがとう、これは私が探していたものです。申し訳ありませんが私の質問が不明な場合、私はASP.NETアイデンティティの "役割"に混乱していた。 –

+0

あなたは歓迎です。実装に何か問題がある場合は、ここでコメントすることをためらってください –

+1

ちょっと、上のコードのuserServiceオブジェクトは何か教えてください。私のDBコンテキストに接続し、私のカスタムユーザをDBから返すカスタムクラスオブジェクトですか?ユーザーはIUserなどの後に継承する必要はありませんか? – Savail

7

はあなたがUserManagerにそれらを注入し、その後、独自のUserStoreUserPasswordStoreクラスを実装する必要があり、デフォルトUserStoreと互換性がありません。この単純な例を考えてみましょう。今、あなたは非常に自身の持っている

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

まず、カスタム・ユーザー・クラスを作成し、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 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ではなくIdentityDbContextからDBコンテキストクラスを直接継承する必要がありますので、独自のユーザーストアを実装していることに注意してください。

関連する問題