1.新建項目並添加引用
新建一個asp .net core 2.0的項目
引用IdentityServer4.AspNetIdentity
2.定義資源
新建Config.cs文件,定義Api資源與Identity資源
資源分為身份資源(Identity resources)和API資源(API resources)
(1)身份資源(Identity resources)
身份資源是用戶的用戶名,姓名或電子郵件地址等數據。身份資源具有唯一的名稱,可以為其分配任意聲明類型。然后,這些聲明將被包含在用戶的身份令牌中。客戶端將使用scope參數來請求訪問身份資源。
身份資源可以是IdentityServer自帶的資源,也可以是自定義的資源。
public static IEnumerable<IdentityResource> GetIdentityResources()
{
//自定義身份資源
var customProfile = new IdentityResource(
name: "custom.profile",
displayName: "Custom profile",
claimTypes: new[] { "name", "email", "status" });
return new List<IdentityResource>
{
//IdentityServer自帶的資源
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
customProfile
};
}
(2)API資源(API resources)
API資源是客戶端訪問API獲得的資源
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>
{
//具有單一范圍的簡單API(在這種情況下,范圍名稱與api名稱相同)
new ApiResource("api1", "My API"),
// 擴展版本,更多的設置選項
new ApiResource
{
Name = "api2",
// 用於內部校驗的密碼
// ApiSecrets是用於內部校驗的,API的名稱(Name)和密碼(ApiSecrets)可以用於認證
ApiSecrets =
{
new Secret("secret".Sha256())
},
// 在訪問令牌中包含以下內容(除了subject ID)
// UserClaims表示用戶聲明
UserClaims = { JwtClaimTypes.Name, JwtClaimTypes.Email },
// // 該API定義了兩個范圍
Scopes =
{
new Scope()
{
Name = "api2.full_access",
DisplayName = "Full access to API 2",
},
new Scope
{
Name = "api2.read_only",
DisplayName = "Read only access to API 2"
}
}
}
};
}
3.定義客戶端Client
客戶端指想要訪問資源的Client
public static IEnumerable<Client> GetClients()
{
return new List<Client>
{
//不一定要配置得這么復雜,根據需求來
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
RequireConsent = true,
ClientSecrets =
{
new Secret("secret".Sha256())
},
//這里配置客戶端的網址,多個客戶端則是多個網址
RedirectUris = { "http://localhost:5002/signin-oidc" },
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
//允許的范圍
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
AllowOfflineAccess = true
}
};
}
其他配置請參閱:
https://identityserver4.readthedocs.io/en/release/topics/clients.html
4.配置
把資源信息和客戶端信息交給IdentityServer
public void ConfigureServices(IServiceCollection services)
{
//配置服務
services.AddIdentityServer()
//讀取客戶端列表
.AddInMemoryClients(Clients.Get())
//讀取身份資源列表
.AddInMemoryIdentityResources(Resources.GetIdentityResources())
//讀取API資源列表
.AddInMemoryApiResources(Resources.GetApiResources())
//設置臨時簽名憑據
.AddDeveloperSigningCredential()
//添加測試用戶
.AddTestUsers(TestUsers.Users);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//配置管道:注意配置管道要寫在路由的前面...
app.UseIdentityServer();
}
這里需要注意的是,以上的資源信息和客戶端信息是存在內存中的,可以設置為讀取數據庫
參閱:https://identityserver4.readthedocs.io/en/release/quickstarts/8_entity_framework.html
5.多客戶端的統一登錄
(1)用戶表
//ApplicationUser繼承於IdentityUser,可以在此為用戶表添加屬性,字段
public class ApplicationUser : IdentityUser
{
}
(2)頁面
<div class="col-md-4">
<section>
<form asp-route-returnurl="@ViewData["ReturnUrl"]" method="post">
<h4>Use a local account to log in.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<!--整個流程是根據郵箱進行注冊和登錄的-->
<label asp-for="Email"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Password"></label>
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<div class="checkbox">
<label asp-for="RememberMe">
<input asp-for="RememberMe" />
@Html.DisplayNameFor(m => m.RememberMe)
</label>
</div>
</div>
<div class="form-group">
<button type="submit" class="btn btn-default">Log in</button>
</div>
<div class="form-group">
<p>
<a asp-action="ForgotPassword">Forgot your password?</a>
</p>
<p>
<a asp-action="Register" asp-route-returnurl="@ViewData["ReturnUrl"]">Register as a new user?</a>
</p>
</div>
</form>
</section>
</div>
(3)登錄方法
這里是AspNet Identity的內容
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
// 嘗試登錄
// 需要注意的是,這里沒有對登錄失敗進行計數
// 為了在登錄失敗多次之后觸發鎖定用戶,把lockoutOnFailure設置為true
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(LoginWith2fa), new { returnUrl, model.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToAction(nameof(Lockout));
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
}
return View(model);
}
6.設置IdentityServer項目的端口號為5000
7.其他
整個流程還需要包括注冊,注銷,忘記密碼,第三方登錄,修改用戶信息等,這些不屬於IdentityServer的討論范疇,在此不做討論