前:IdentityServer4は、シングルサインオンを実現OpenIdConnectを使用します。
前の例で記述され、メモリキャッシュのストレージを使用してIdeneityServer、すべての構成がConfig.cs年に書かれています。実際には、あなたがそのような新しいユーザー、リソース、クライアントを追加するなど、いつでも都合の良い設定で、データベースストレージを使用する必要があり、あなたはまた、サーバのメモリを節約することができます。
三つの側面からMySQLは、データベースストレージを実装し、各クライアントとリソースのデータ、およびトークン認証コードデータとユーザデータバインディングIdentityServer4を達成しています。
まず、コンテンツを準備
1は、MySQLデータベースサーバーへの準備ができて、新しい空のデータベースを作成します
2、IdentityServerは、いくつかのパッケージをインストールする必要があります。
IdentityServer4.EntityFramework Microsoft.EntityFrameworkCore.Tools Pomelo.EntityFrameworkCore.MySql(:MySql.Data.EntityFrameworkCoreあなたものMySQLの公式パッケージを使用することができます)
3、appsettings.jsonデータベース接続文字列を追加します
{ "のconnectionStrings":{ "MySqlDbConnectString": "サーバー= IP;ユーザーID = mysqlUserName; PWD =ユーザのパスワード;データベース=データベース名;のConnectionTimeout = 30;プール=真;最大プールサイズ= 300;分プールサイズ= 5;" } }
第二に、クライアントとデータベース・ストレージ・リソース
以前の私たちは、コンフィギュレーション・データをロードするためにAddInMemory方法を使用します
AddInMemoryIdentityResources(Config.GetIdentityResources()) AddInMemoryApiResources(Config.GetApis()) AddInMemoryClients(Config.GetClients())
次の3行のコードをコメントアウトし、次のコードを交換
VAR接続= Configuration.GetConnectionString( "MySqlDbConnectString"); VARビルダー= services.AddIdentityServer() //身份信息资源 //。AddInMemoryIdentityResources(Config.GetIdentityResources()) .AddConfigurationStore(OPT => { opt.ConfigureDbContext =コンテキスト=> { context.UseMySql(接続、SQL => { SQL .MigrationsAssembly( "IdentityServer"); }); }; }) .AddTestUsers(Config.GetUsers());}
確かに、対応するデータテーブルを追加する必要があり、IdentityServerプロジェクトは、パッケージマネージャコンソールを開き、プロジェクトを開始するように設定されているデータベースのクエリから構成データは、コンソールで次のコマンドを入力しIdentityServerコンソール、デフォルトのプロジェクトを設定します
PM>アドオンの移行をConfigDbContext -c ConfigurationDbContext -oデータ/移行/ IdentityServer / PersistedGrantDb このアクションを元に戻すには、削除・マイグレーションを使用しています。 PM>更新データベースが 完了します。
-c ConfigurationDbContextは、現在のデータベースコンテキストが指定されています。名前空間で定義されてConfigurationDbContext:IdentityServer4.EntityFramework.DbContexts、そして昨日、彼らはCodeFirst、クライアントとデータテーブルとテーブルに関連付けられたリソースの定義を使用します。アドオン移行世代移動度シフト記録を更新 - datase日にデータベースを更新します。
しかし、今のデータベースクライアントとリソースのデータが空になっている、あなたがデータベースにコンフィグ設定データを追加する必要がある、あなたはStart.csで、データベースの初期化メソッドを追加することができます
プライベートボイドInitializeDatabase(IApplicationBuilderアプリ) { 使用(VAR serviceScope = app.ApplicationServices.GetService <IServiceScopeFactory>()CreateScope()) { VARコンテキスト= serviceScope.ServiceProvider.GetRequiredService <ConfigurationDbContext>(); (もし!context.Clients.Any()) { foreachの(Config.GetClients中のvarクライアント()) { context.Clients.Add(client.ToEntity()); } context.SaveChanges()。 } もし(!context.IdentityResources.Any()) { foreachの(Config.GetIdentityResourcesにおけるVARリソース()) { context.IdentityResources.Add(resource.ToEntity())。 } context.SaveChanges()。 } (!context.ApiResources.Any())なら 、{ foreachの(Config.GetApisにおけるVARリソース()) { context.ApiResources.Add(resource.ToEntity())。 } context.SaveChanges()。 } } }
説明:app.ApplicationServices.GetServiceを使うには<IServiceScopeFactory>()CreateScopeは、他のコンテキストの解放の範囲には影響しない、新しいサービスのスコープを作成し、他のスコープから分離され、オペレーティングエンティティは、データベースを更新するために、我々は通常、同じを使用します。プログラムを実行した後、私たちは、データベースがすでにデータを持っていることがわかりました
テスト実行IdentityServer、IdentityMvc、IdentityApi三つのプログラム
第二に、トークンと認証コードは、データベースに格納されています
IIdentityServerBuilder拡張書き込み方法のAddOperationalStoreを使用します
//クライアントとリソースデータベースを格納するコンフィギュレーション .AddConfigurationStore(OPT => { opt.ConfigureDbContextコンテキスト= => { context.UseMySql(接続、SQL => { sql.MigrationsAssembly( "IdentityServer"); }); }; }) //トークンデータベースを格納するコンフィギュレーション及び認証コード .AddOperationalStore(OPT => { opt.ConfigureDbContextコンテキスト= => { context.UseMySql(接続、SQL => { sql.MigrationsAssembly( "IdentityServer")。 }); }。 opt.EnableTokenCleanup =はtrue。 opt.TokenCleanupInterval = 30。 }) .AddTestUsers(Config.GetUsers())。
同様に、必要が格納するデータテーブルを追加します
PM>アドオンの移行をのOperationContext -c PersistedGrantDbContext -oデータ/移行/ IdentityServer / OperationDb 設定された複数のスタートアッププロジェクト。 PM>更新-データベース-c PersistedGrantDbContext 完了。
テスト実行IdentityServer、IdentityMvc、IdentityApi三つのプログラム
第三に、ユーザ・データベース・ストレージ
IdentityServer4 IIdentityServerBuilderは、トークン認証コードとデータベースストレージAddOperationalStoreをサポートするためのクライアント・データベースストレージAddConfigurationStore方法へのサポートとリソースを提供しますが、ユーザーのデータベース・ストレージ・メソッドを提供していませんでした。クライアントのストレージ構造、資源、トークン、認証コードが必須ですので、私は、ユーザー、ユーザー定義のすべての人のリソース、役割、権限、およびその他の基本的な情報の格納構造が異なっているのではなく、と思います。しかしいいえ、あなたはユーザーデータベースのストレージをサポートして独自の模造AddConfigurationStore AddUserStoreメソッドを書くことができます。
IdentityUserStoreフォルダと呼ばれる新しいファイルを作成するために、IdentityServerプロジェクトでは、4つのクラスを作成します
IdentityServer.IdentityUserStore.IdentityUser:ユーザエンティティ
パブリッククラスIdentityUser { [キー] [必須] パブリック文字列SubjectId {取得します。セットする; } [必須] パブリック文字列ユーザー名{得ます。セットする; } [必須] パブリック文字列のパスワード{得ます。セットする; } パブリック文字列はProviderName {得ます。セットする; } パブリック文字列ProviderSubjectId {得ます。セットする; } パブリックブールのisActive {得ます。セットする; }
パブリックいるICollection <IdentityUserClaim> IdentityUserClaims {得ます。セットする; } } publicクラスIdentityUserClaim { [キー] パブリック文字列ClaimId {得ます。セットする; } [必須] パブリック文字列名{得ます。セットする; } [必須] パブリック文字列値{得ます。セットする; } [必須] パブリック文字列UserSubjectId {得ます。セットする; } [ForeignKeyの( "UserSubjectId")] パブリック仮想IdentityUser IdentityUser {得ます。セットする; } }
IdentityServer.IdentityUserStore.UserStoreDbContext:データベースPersistedGrantDbContextとして動作コンテキスト、および以前に使用ConfigurationDbContextの役割を定義します
パブリッククラスUserStoreDbContext:DbContext { 公共UserStoreDbContext(DbContextOptionsがオプトイン):塩基(OPT) { } 公共DbSet <IdentityUser> IdentityUser {得ます。セットする; } 公共DbSet <IdentityUserClaim> IdentityUserClaim {得ます。セットする; } }
IdentityServer.IdentityUserStore.UserStore:ユーザー情報とパスワードの検証を照会するために使用
パブリッククラスUSERSTORE { プライベート読み取り専用UserStoreDbContext _dbContext。 公共USERSTORE(UserStoreDbContext dbContext) { _dbContext = dbContext。 } /// <要約> ///根据SubjectID查询用户信息 /// </要約> /// <PARAM NAME = "subjectId">用户ID </ PARAM> /// <戻る> </戻る> 公衆IdentityUser FindBySubjectId(文字列subjectId){ 。。_dbContext.Setを返す<IdentityUser>()ここで(R => r.SubjectId.Equals(subjectId))も含める(R => r.IdentityUserClaims).SingleOrDefault(); } /// <要約> /// </要約> /// <PARAM NAME = "ユーザ名">用户</ PARAM> /// <戻る> </戻り> 公共IdentityUser FindByUsername(文字列名) { 戻り_dbContext.Set <IdentityUser>() .Where(R => r.Username.Equals(ユーザ名))も含める(R => r.IdentityUserClaims).SingleOrDefault()。 } /// <要約> ///验证登录密码 /// </要約> /// <PARAM NAME = "ユーザ名"> </ param>の /// <PARAM NAME = "パスワード"> </ param>の /// <リターン> </リターン> 公共ブールValidateCredentials(文字列のユーザー名、 && r.Password.Equals(パスワード))も含める(R => r.IdentityUserClaims).SingleOrDefault()。 !リターンユーザー= NULL; } }
IdentityServer.IdentityUserStore.IIdentityServerBuilderUserStoreExtensions:UserStoreDbContext、UserStoreDbContextサービスの依存関係を追加し、展開するIIdentityServerBuilderを書きます。
パブリック静的クラスIIdentityServerBuilderUserStoreExtensions { パブリック静的IIdentityServerBuilder AddUserStore(このIIdentityServerBuilderビルダー、アクション<DbContextOptionsBuilder> userStoreOptions = NULL) { builder.Services.AddDbContext <UserStoreDbContext>(userStoreOptions)。 builder.Services.AddTransient <USERSTORE>(); ビルダーを返します。 } }
AddTestUser(Config.GetUsers)を交換するために、次のコードStartup.ConfigureServicesプロセスにおいて
// AddTestUsers(Config.GetUsers()) .AddUserStore(OPT => { opt.UseMySql(接続、SQL => { sql.MigrationsAssembly( "IdentityServer"); }); })
データテーブルを格納するためのユーザーの追加、パッケージマネージャでコマンドを入力します。
PM>アドオン移行UserStoreContext -c UserStoreDbContext -oデータ/移行/ IdentityServer / userdbの PM>更新-データベースUserStoreDbContext -c 設定された複数のスタートアッププロジェクト。 スタートアッププロジェクトとしてプロジェクト「のsrc \のIdentityServer」を使用。 完了。 PM>
データベースクラス構成初期プロセス内のユーザデータを追加します
プライベートボイドInitializeDatabase(IApplicationBuilderアプリ) { 使用(VAR serviceScope = app.ApplicationServices.GetService <IServiceScopeFactory>()CreateScope()) { VARコンテキスト= serviceScope.ServiceProvider.GetRequiredService <ConfigurationDbContext>(); VAR userContext = serviceScope.ServiceProvider.GetRequiredService <UserStoreDbContext>(); //添加設定中的客户端数据到数据库 場合(context.Clients.Any()!) { foreachの(Config.GetClients中のvarクライアント()) { context.Clients.Add(client.ToEntity()); } context.SaveChangesは(); } //データベースのコンフィグIdentityResourcesにデータを追加 IF(!context.IdentityResources.Any()) { foreachの(Config.GetIdentityResources中のvarリソース()) { context.IdentityResources.Add(resource.ToEntity ()); } context.SaveChanges(); } ApiResources //データベースの設定にデータを追加 !IF(context.ApiResources.Any()) { foreachの(Config.GetApisにおけるVARリソース()) { context.ApiResources.Add(resource.ToEntity())。 } context.SaveChanges()。 } //添加コンフィグ中的ユーザー数据到数据库 IF(userContext.IdentityUser.Any()!) { int型のインデックス= 0。 foreachの(Config.GetUsersにおけるVARユーザー()) { IdentityUser IUSER =新しいIdentityUser() { のisActive = user.IsActive、 パスワード= user.Password、 はProviderName = user.ProviderName、 ProviderSubjectId = user.ProviderSubjectId、 SubjectId = user.SubjectId、 ユーザ名= user.Username、 IdentityUserClaims = user.Claims.Select(R =>新しいIdentityUserClaim() { ClaimId =(インデックス++)。ToStringメソッド()、 NAME = r.Type、 値= r.Value 。})ToListメソッド() ;} userContext.IdentityUser.Add(IUSER)。 } userContext.SaveChanges()。 } } }
データベースは、ユーザー・データを持って見ることができます
最後のステップは、ログインとパスワード情報ユーザーのクエリを確認するために、上記の新しいUSERSTOREクラスを使用して、ユーザーが主張を追加します。
AccountControllerコンストラクタ
//プライベート読み取り専用TestUserStoreの_users。这里改成了USERSTORE プライベート読み取り専用のUSERSTOREの_users。 プライベート読み取り専用IIdentityServerInteractionServiceの_interaction。 プライベート読み取り専用IClientStore _clientStore。 プライベート読み取り専用IAuthenticationSchemeProvider _schemeProvider。 プライベート読み取り専用IEventServiceの_events。 公共AccountController( IIdentityServerInteractionServiceの相互作用、 IClientStore clientStore、 IAuthenticationSchemeProvider schemeProvider、 IEventServiceイベント、 // TestUserStore _users = nullを、这里改成了USERSTORE USERSTOREユーザ) { // _users =ユーザー?新しいTestUserStore(Config.GetUsers()); 这里改成了USERSTORE _users =ユーザー; _interaction =相互作用; _clientStore = clientStore。 _schemeProvider = schemeProvider。 _events =イベント。 }
タスク<IActionResult>ログイン(LoginInputModelモデル、ストリングボタン)、データベースIdentityUserClaims内のログデータがオーバーロードされたメソッドにログデータを特徴とする変換。
リスト<項>クレーム= user.IdentityUserClaims.Select(R =>新しいクレーム(r.Name、r.Value)).ToList(); 待つHttpContext.SignInAsync(user.SubjectId、user.Username、小道具、claims.ToArray())。
ファイル名を指定して実行IdentityServer、IdentityApi、IdentityMvc 3つのプロジェクトの登録機関の後に - access_token-アクセスAPIを取得