IdentityServer4【QuickStart】之利用OpenID Connect添加用戶認證


利用OpenID Connect添加用戶認證

利用OpenID Connect添加用戶認證

在這個示例中我們想要通過OpenID Connect協議將交互用戶添加到我們的IdentityServer上面。

准備就緒后,我們會創建一個MVC的應用來使用IdentityServer做認證。

添加UI

關於該協議支持所需要的一切都內建到了IdentityServer中,你需要為登陸、登出、確認和錯誤等提供必要的UI頁面。

雖然在每一個實現了IdentityServer的服務中它所實現的外觀和工作流程等都是不一樣的,我們提供了一個MVC模板,你可以將其作為起點。

可以從 Quickstart UI repo找到這個示例。你可以(使用github)克隆或者下載到你的桌面然后將控制器、視圖、模型和Css樣式表等放到你的應用里面。

你也可以在你的項目的根目錄下面運行下面這個命令行(在powershell)進行自動的安裝:

iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/IdentityServer/IdentityServer4.Quickstart.UI/release/get.ps1'))

 

一點你安裝好了這些之后,你也需要在Startup類中配置好你的MVC,這需要在ConfigureService里面將MVC添加到DI中並在Configure方法中將MVC中間件添加到管道上。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
 
    // configure identity server with in-memory stores, keys, clients and scopes
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(Config.GetUsers());
}

並且應該將MVC作為管道的最后一個中間件:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
 
    app.UseIdentityServer();
 
    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
}

 

readme可以看到更多的信息。

花費一些時間檢查以下控制器和模型,你越了解他們,在后續的升級和改造過程中也會越容易。大多數代碼都保存在一個QuickStart的文件夾中。如果這種方式不適合你的話,你可以自己修改成你要的風格。

創建一個MVC客戶端

下一步你得創建一個MVC的應用。使用Asp.net core自帶的模板就可以。不要配置認證信息。關於認證的信息需要你在應用里面自己配置。一旦你創建好應用后,將應用的端口號配置到5002上面。

為了添加對OpenID Connect認證的支持,需要在Startup類中的ConfigureService方法中進行如下的配置。

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
 
    JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
 
    services.AddAuthentication(options =>
        {
            options.DefaultScheme = "Cookies";
            options.DefaultChallengeScheme = "oidc";
        })
        .AddCookie("Cookies")
        .AddOpenIdConnect("oidc", options =>
        {
            options.SignInScheme = "Cookies";
 
            options.Authority = "http://localhost:5000";
            options.RequireHttpsMetadata = false;
 
            options.ClientId = "mvc";
            options.SaveTokens = true;
        });
}

 

AddAuthentication 方法將認證服務添加到了DI系統中,我們使用了一個cookie作為認證用戶的主要手段(通過options.DefaultScheme=“Cookies”來指定)。我們將DefaultChallengeScheme設置成“oidc”使用為當我們需要用戶登陸的時候,我們要使用OpenID Connect的scheme。

然后我們使用AddCookie方法添加一個對應的處理Cookie的handler(對應於options.DefaultScheme=“”Cookies“這個配置)。

最后,AddOpenIdConnect方法配置了相應的handler(對應於options.DefaultChallengeScheme=”oidc”)來執行OpenID Connect協議。Authority指定了我們要新人的IdentityServer;然后通過ClientId標志了客戶端;SiginScheme=“Cookies“這個表示當OpenId Connect協議執行完成之后會使用cookie handler來發布cookie。

此外,我們關閉了JWT claim的類型映射以允許OpenId Connect中的claim類型。

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
然后為了認證服務會在每個請求中都執行,需要在Startup類中的Configure方法中配置認證的中間件:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }
 
    app.UseAuthentication();
 
    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
}

 

認證中間件應該放在MVC的前面。

最后一步是要觸發認證。我們需要在home控制器上面添加[Autorize]特性。同時修改一下about頁面:

<dl>
    @foreach (var claim in User.Claims)
    {
        <dt>@claim.Type</dt>
        <dd>@claim.Value</dd>
    }
</dl>

 

如果你現在使用瀏覽器訪問了剛才配置好的控制器的路徑,那么會有一個重定向發送到IdentityServer。這回導致一個錯誤因為MVC客戶端還沒有注冊到Identityserver。

添加對OpenID Connect Identity Scopes的支持

和OAuth2.0相似的是,OpenID Connect同樣使用了scopes這個概念。再一次聲明:scopes代表了你想要保護的,同時,也是客戶端想要訪問的那種東西。與OAuth對比一下,scopes在OIDC中並不代表APIs,而是代表了用戶的數據,比如user id、name或者email等。

在這里闡述一下:scopes在OIDC里面是和claim掛鈎的,他們之間的關系是1對多。打個比方,profile里面包含了許多的claim,包括first_name last_name等等。。

在Config類中添加一個幫助方法,這個方法創建了一個IdentityResource的集合,它添加了對標准openid(subject id)和profile(用戶的名、姓等等)scopes的支持。

public static IEnumerable<IdentityResource> GetIdentityResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile(),
    };
}

所有標准scopes對應的claims都能在specification找到。

然后你得將上面配置好的添加到ConfgureService方法中,使用AddInmemoryIdentityResource:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
 
    // configure identity server with in-memory stores, keys, clients and scopes
    services.AddIdentityServer()
        .AddDeveloperSigningCredential()
        .AddInMemoryIdentityResources(Config.GetIdentityResources())
        .AddInMemoryApiResources(Config.GetApiResources())
        .AddInMemoryClients(Config.GetClients())
        .AddTestUsers(Config.GetUsers());
}

添加一個客戶端用於演示OpenID Connect的隱式流程

最后一步是在IdentityServer中為MVC客戶端添加一個新的入口。

在IdentitySErver中配置基於OpenId Connect的客戶端和配置OAuth2.0的客戶端有些相似。但是因為在OpenID Connect中經常會有交互發生,所有我們需要在配置中添加一寫重定向。

在客戶端配置的代碼中寫入如下:

public static IEnumerable<Client> GetClients()
{
    return new List<Client>
    {
        // other clients omitted...
 
        // OpenID Connect implicit flow client (MVC)
        new Client
        {
            ClientId = "mvc",
            ClientName = "MVC Client",
            AllowedGrantTypes = GrantTypes.Implicit,
 
            // where to redirect to after login
            RedirectUris = { "http://localhost:5002/signin-oidc" },
 
            // where to redirect to after logout
            PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
 
            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile
            }
        }
    };
}

 

測試客戶端

現在終於都辦妥了。

導航到被保護的控制器上以便觸發認證,這時你會發現被重定向到了IdentitySErver上的登陸頁面:

 

 

登陸成功后,會給用戶呈現一個確認頁面。在這里用戶可以決定他是否要將一些訪問資源的權限交給客戶端。

確認頁面可以在配置中的RequireConsent屬性上取消。

 

 

最終頁面會跳轉到客戶端應用上,展示用戶的claim。

 

添加登出

在添加一個登出的功能吧。

使用像identity server這樣的身份驗證服務,只需要清除本地應用程序cookie就不夠了。此外,你還需要對身份服務器進行一次往返,以清除中心單點登錄會話。

確切的協議步驟是在OpenID Connect中間件中實現的,只需將以下代碼添加到某個控制器中以觸發信號:

public async Task Logout()
{
    await HttpContext.SignOutAsync("Cookies");
    await HttpContext.SignOutAsync("oidc");
}

這將會清除本地的cookie然后重定向到Identityserver。Identtiyserver會清除它的Cookie然后給用戶一個返回MVC應用的鏈接。

進一步的嘗試

就像上面提到的,OpenId Connect中間件默認會請求profile scope。這個scope中包含了諸如name website等claim。

將這些claim添加到TestUser上面,這樣一來IdentityServer可以將他們放到Id token里面:

public static List<TestUser> GetUsers()
{
    return new List<TestUser>
    {
        new TestUser
        {
            SubjectId = "1",
            Username = "alice",
            Password = "password",
 
            Claims = new []
            {
                new Claim("name", "Alice"),
                new Claim("website", "https://alice.com")
            }
        },
        new TestUser
        {
            SubjectId = "2",
            Username = "bob",
            Password = "password",
 
            Claims = new []
            {
                new Claim("name", "Bob"),
                new Claim("website", "https://bob.com")
            }
        }
    };
}

 

下一次你再認證的時候,你的展示claims的頁面就會展示這些額外的claim了。

試着任意添加一些claim,或者更多的scopes。在OpenId Connect中間件中的Scope屬性上面進行的配置會決定你發送到IdentityServer的認證請求中會包含那些scopes:

services.AddAuthentication(option =>

            {

                option.DefaultScheme = "cookies";

                option.DefaultChallengeScheme = "oidc";

            }).AddCookie("cookies").AddOpenIdConnect("oidc", option =>

            {

                option.Scope.Add("somescope");//這句

            });

 

同樣值得注意的是,檢索令牌的claim是一個可擴展點----IProfileService。因為我們使用AddTestUsers,TestUserProfileService是默認被使用的。你可以檢查源代碼here 來看看它是如何工作的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM