預備知識: http://www.cnblogs.com/cgzl/p/7746496.html 第一部分: http://www.cnblogs.com/cgzl/p/7780559.html 第二部分: http://www.cnblogs.com/cgzl/p/7788636.html 第三部分: http://www.cnblogs.com/cgzl/p/7793241.html 第四部分: http://www.cnblogs.com/cgzl/p/7795121.html
之前的配置都是在記憶體中, 下面将如何把這些資料存儲到Sql Server資料庫, 這樣更适合生産環境.
這部分基本完全參考官方文檔:
https://identityserver4.readthedocs.io/en/release/quickstarts/8_entity_framework.html安裝Entity Framework相關的庫
為Authorization Server 添加 IdentityServer4.EntityFramework:

還需要安裝Microsoft.EntityFrameworkCore.SqlServer:
最後是Microsoft.EntityFrameworkCore.Tools:
使用它可以進行遷移等操作.
然後使用指令行進入Auth Server項目的目錄, 試一下dotnet ef指令:
很不幸, 沒找到dotnet ef指令. 這裡需要手動修改AuthServer的項目檔案, 右鍵點選項目, 點選Edit AuthServer.csproj.
這部分操作的官方文檔在這:
https://docs.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet我們需要添加這部分代碼:
<ItemGroup>
<DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>
然後回到指令行, 再執行 dotnet ef:
這次好用了. 接下來就是add migrations了.
幸運的是, 之前裝的庫裡面有封裝好的model, 它們可以自動建立migration檔案.
這裡一共有兩個指令(migrations), 一個是為了IdentityServer的配置, 另一個是為了持久化授權.
dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb
運作發現了問題, 這是因為我們還沒有配置AuthServer來使用資料庫.
添加appSettings.json, 并指定連接配接字元串:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=AuthServer;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
修改Startup.cs:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddIdentityServer()
// .AddDeveloperSigningCredential()
.AddSigningCredential(new X509Certificate2(@"D:\Projects\test\socialnetwork.pfx", "Bx@steel"))
.AddTestUsers(InMemoryConfiguration.Users().ToList())
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
});
services.AddMvc();
}
首先擷取資料庫連接配接字元串, 然後添加兩部配置設定置, 一個是配置資料(clients, resources), 一個是操作資料(tokens, codes, consents同意).
再次運作指令行:
dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb
好用了.
看看生成的檔案, 是有這兩部分:
看一下檔案的内容, 會發現有很多的Table.
下一步就是添加自動遷移, 暫且在StartUp裡面找個位置建立個方法吧:
private void InitializeDatabase(IApplicationBuilder app)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
context.Database.Migrate();
if (!context.Clients.Any())
{
foreach (var client in InMemoryConfiguration.Clients())
{
context.Clients.Add(client.ToEntity());
}
context.SaveChanges();
}
if (!context.IdentityResources.Any())
{
foreach (var resource in InMemoryConfiguration.IdentityResources())
{
context.IdentityResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiResources.Any())
{
foreach (var resource in InMemoryConfiguration.ApiResources())
{
context.ApiResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
}
}
首先是分别對兩個context進行遷移, 然後判斷是否這些表裡是空的, 如果沒有資料, 就把配置的記憶體資料添加到資料庫裡面.
别忘了在Configure方法調用:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
InitializeDatabase(app);
app.UseDeveloperExceptionPage();
app.UseIdentityServer();
app.UseStaticFiles();
app.UseMvcWithDefaultRoute();
}
運作項目, 重新操作一下登陸, 同意的過程, 依然好用.
看一下資料庫:
确實生成了很多表.
檢視Clients表, 裡面有三條資料.
PersistedGrants裡面也有一條資料. 登陸時當你同意請求許可的時候, 就會在這個表裡面添加一條資料.
把使用者存儲到資料庫
可以使用自定義的使用者表來存儲使用者資料, 但是我要用的是asp.net core identity, 是以我就不講别的方式了.
不過首先, 需要重建個項目, 并且把之前講的所有内容都操作一遍, 因為這裡要使用asp.net core mvc 模闆并使用Individual User Account的驗證方式:
建立好項目後, 需要把之前講的所有步驟操作一下, 然後安裝: IdentityServer4.AspNetIdentity:
修改Startup, 大約成為這個樣子, 隻看紅色部分即可:
namespace AuthorizationServer
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
services.AddIdentity<ApplicationUser, IdentityRole>(options =>
{
// Password settings
options.Password.RequireDigit = false;
options.Password.RequiredLength = 6;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequireLowercase = false;
options.Password.RequiredUniqueChars = 2;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// Signin settings
options.SignIn.RequireConfirmedEmail = false;
options.SignIn.RequireConfirmedPhoneNumber = false;
// User settings
options.User.RequireUniqueEmail = false;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddTransient<IEmailSender, EmailSender>();
services.AddMvc();
services.AddIdentityServer()
.AddDeveloperSigningCredential()
// .AddSigningCredential(new X509Certificate2(@"D:\Projects\test\socialnetwork.pfx", "password"))
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationsAssembly));
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
})
.AddAspNetIdentity<ApplicationUser>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.InitializeDatabase();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentityServer();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
注意在Configure方法裡面不要使用app.UseAuthentication(), 因為app.UseIdentityServer()方法已經包含了這個中間件. 然後使用指令行執行:
dotnet ef database update
或者在Packge Manager Console執行 update-database也行.
我照着官方文檔操作出現了一些問題, 有幾個重複的controller, 因為項目建立好之後有個HomeController和AccountController, 而使用Quickstart UI裡面也有這兩個Controller.
是以我最後clone了官方的例子:
https://github.com/IdentityServer/IdentityServer4.Samples/tree/dev/Quickstarts/6_AspNetIdentity修改了一下, 放到了我這個項目裡:
https://github.com/solenovex/Learning-Identity-Server-4其他
有的項目可能需要使用第三方登陸, 例如使用Google賬戶, 微軟賬戶, QQ等, 這部分請看官方文檔自行學習吧. 我要做的是企業内部項目. 是以這塊先不研究了.
也有可能會使用Auth0, Stormpath這樣的OAuth Provider, Auth0我用過, 登陸有點慢, 但功能很強大. 這個也不講了, 他們的文檔寫的很好, 也給出了各種用戶端的代碼, 很容易內建.
Javascript 用戶端
這将是最後一部分.
手頭的項目有點急. 過幾天再寫這個.
下面是我的關于ASP.NET Core Web API相關技術的公衆号--草根專欄: