既存のMySQLデータベース用のWebAPI C#アプリケーションを作成する必要があります。 Entity Framework 6を使用して、すべてのデータベーステーブルをRESTful API(CRUD操作を可能にする)にバインドすることができました。
ログイン/登録システムを実装したい(将来的にロールと権限を実装し、特定のAPIリクエストを制限できるようにするため)。
私が使用しなければならないMySQLデータベースには、ユーザー用のテーブル(user
と呼ばれます)があり、次の自明の列があります。
id
email
username
password_hash
認証のデファクトスタンダードはASP.NetIdentityのようです。私はこの1時間、既存のDB-First EntityFrameworkセットアップでIdentityを機能させる方法を見つけようとしてきました。
ApplicationUser
インスタンス(MySQLデータベースからのエンティティ)を格納するuser
インスタンスを構築して、ユーザーデータを取得しようとすると、次のエラーが発生します:
エンティティタイプApplicationUserは、現在のコンテキストのモデルの一部ではありません。
MySQLデータベースにIDデータを保存する必要があると思いますが、その方法に関するリソースが見つかりませんでした。 ApplicationUser
クラスを完全に削除し、user
エンティティクラスをIdentityUser
から派生させようとしましたが、UserManager.CreateAsync
を呼び出すと、LINQからエンティティへの変換エラーが発生しました。
既存のuser
エンティティを持つWebAPI 2アプリケーションで認証を設定するにはどうすればよいですか?
あなたは言う:
ログイン/登録システムを実装したい(将来、ロールと権限を実装し、特定のAPIリクエストを制限できるようにするため)。
既存のユーザーエンティティを持つWebAPI 2アプリケーションで認証を設定するにはどうすればよいですか?
それは間違いなくあなたがしないでください ASP.NETIdentityが必要であることを意味します。 ASP.NET Identityは、すべてのユーザーのものを処理するテクノロジです。実際には、認証メカニズムを「作成」しません。 ASP.NET Identityは、OWIN認証メカニズムを使用します。これは別のことです。
探しているのは"既存のUsersテーブルでASP.NETIDを使用する方法"ではなく"既存の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
ファイルを作成します(例):
[アセンブリ: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]
属性を使用して、アクションを承認します。
GrantType
、UserName
、およびPassword
を指定してapi/security/token
を呼び出し、ベアラートークンを取得します。このような:
"grant_type=password&username=" + username + "&password=" password;
HttpHeader Authorization
内のトークンをBearer "YOURTOKENHERE"
として送信します。このような:
headers: { 'Authorization': 'Bearer ' + token }
それが役に立てば幸い!
DBスキーマはデフォルトのUserStore
と互換性がないため、独自のUserStore
クラスとUserPasswordStore
クラスを実装してから、それらを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
}
次に、カスタムのUserStore
クラスとIUserPasswordStore
クラスを次のように作成します。
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クラスをDbContext
ではなくIdentityDbContext
から直接継承する必要があることに注意してください。