IdentityServer4(三):基於ASP.NET Core的交互式認證授權

基於ASP.NET Core的交互式認證授權

上一篇中已經添加了一個認證授權中心服務,本篇在此前的基礎上進行擴展,通過添加OpenID Connect協議以支持交互式用戶身份驗證。

本示例代碼中,認證授權中心運行在http://localhost:5000下,ASP.NET Core MVC 客戶端網站運行在http://localhost:5002

演示效果

訪問:http://localhost:5002/home/authinfo(此站點已配置爲所有頁面都需要授權才能訪問)
如圖,訪問此站點後重定向到認證授權中心:http://localhost:5000。在認證授權中心輸入憑據後,重新返回之前的訪問頁面。
在這裏插入圖片描述
打開開發者工具,可以看到相關cookie已寫入:
在這裏插入圖片描述

服務端配置示例

  • 在Config中添加客戶端信息

基於OpenID Connect的客戶端與我們添加的OAuth 2.0客戶端非常相似。但是,由於OIDC中的流始終是交互式的,因此我們需要在配置中添加一些重定向URL。

public static IEnumerable<Client> Clients => new List<Client>
{
    new Client
    {
        ClientId="mvc",
        ClientSecrets={new Secret("secret".Sha256())},

        AllowedGrantTypes=GrantTypes.Code,
        RequireConsent=false,
        RequirePkce=true,

        RedirectUris={ "http://localhost:5002/signin-oidc"},

        PostLogoutRedirectUris={ "http://localhost:/5002/signout-callback-oidc"},

        AllowedScopes=new List<string>{
            IdentityServerConstants.StandardScopes.OpenId,
            IdentityServerConstants.StandardScopes.Profile
        }
    }
};
  • 在Config中添加對OpenID Connect Identity Scope的支持

OAuth 2.0相似,OpenID Connect也使用範圍概念。同樣,範圍代表我們要保護的內容以及客戶端要訪問的內容。與OAuth相比,OIDC中的範圍不代表API,而是諸如用戶ID姓名電子郵件地址之類的身份數據。

// Defineing Identity Resource
public static IEnumerable<IdentityResource> Ids => new List<IdentityResource>
{
    new IdentityResources.OpenId(),
    new IdentityResources.Profile()
};
  • 添加測試用戶
public class TestUsers
{
    public static List<TestUser> Users = new List<TestUser>
    {
        new TestUser{SubjectId = "818727", Username = "張三", Password = "123456",
            Claims =
            {
                new Claim(JwtClaimTypes.Name, "張三"),
                new Claim(JwtClaimTypes.GivenName, "三"),
                new Claim(JwtClaimTypes.FamilyName, "張"),
                new Claim(JwtClaimTypes.Email, "[email protected]"),
                new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
                new Claim(JwtClaimTypes.WebSite, "http://zhangsan.com"),
                new Claim(JwtClaimTypes.Address, @"{ '城市': '杭州', '郵政編碼': '310000' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json)
            }
        }
    };
}
  • 添加服務到DI
public void ConfigureServices(IServiceCollection services)
{
    var builder = services.AddIdentityServer()
        .AddInMemoryIdentityResources(Config.Ids)
        .AddInMemoryApiResources(Config.Apis)
        .AddInMemoryClients(Config.Clients)
        .AddTestUsers(TestUsers.Users);
    builder.AddDeveloperSigningCredential();
}

創建一個MVC客戶端網站

Install-Package Microsoft.AspNetCore.Authentication.OpenIdConnect -Version 3.1.0

  • 添加服務到DI
public void ConfigureServices(IServiceCollection services)
{
	// 我們使用cookie來本地登錄用戶(通過“Cookies”作爲DefaultScheme),並且將DefaultChallengeScheme設置爲oidc。因爲當我們需要用戶登錄時,我們將使用OpenID Connect協議。
	services.AddAuthentication(options =>
	{
	    options.DefaultScheme = "Cookies";
	    options.DefaultChallengeScheme = "oidc";
	})
	// 添加可以處理cookie的處理程序
	.AddCookie("Cookies")
	// 用於配置執行OpenID Connect協議的處理程序
	.AddOpenIdConnect("oidc", options =>
	{
	    options.Authority = "http://localhost:5000";    // 受信任令牌服務地址
	    options.RequireHttpsMetadata = false;
	
	    options.ClientId = "mvc";
	    options.ClientSecret = "secret";
	    options.ResponseType = "code";
	
	    options.SaveTokens = true;  // 用於將來自IdentityServer的令牌保留在cookie中
	});
}
  • 確保服務對每個請求執行驗證
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseStaticFiles();
    
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}")
        .RequireAuthorization();    // RequireAuthorization方法禁用整個應用程序的匿名訪問
    });
}
  • 添加控制器方法
public class HomeController : Controller
{
    public IActionResult AuthInfo()
    {
        return View();
    }
}
  • 添加視圖
@using Microsoft.AspNetCore.Authentication;
<div class="text-left">
    <h2>Claims</h2>
    <table class="table">
        <thead>
            <tr>
                <th scope="col">Claim Type</th>
                <th scope="col">Claim Value</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var claim in User.Claims)
            {
                <tr>
                    <td>@claim.Type</td>
                    <td>@claim.Value</td>
                </tr>
            }
        </tbody>
    </table>
    
    <h2>Properties</h2>
    <table class="table">
        <thead>
            <tr>
                <th scope="col">Claim Type</th>
                <th scope="col">Claim Value</th>
            </tr>
        </thead>
        <tbody>
            @foreach (var prop in (await Context.AuthenticateAsync()).Properties.Items)
            {
                <tr>
                    <td>@prop.Key</td>
                    <td>@prop.Value</td>
                </tr>
            }
        </tbody>
    </table>
</div>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章