IdentityServer4_2.使用 ASP.NET Core 的交互式应用程序

使用Asp.net Core的交互式应用程序

OIDC:OpenID Connect协议

OpenID Connect是基于OAuth 2.0规范族的可互操作的身份验证协议。它使用简单的Rest/JSON消息流来实现,和之前任何一种身份认证协议相比开发者可以轻松集成。

OpenID Connect允许开发者验证跨网站和应用的用户,而无需拥有和管理密码文件。OIDC允许所有类型的客户,包括基于浏览器的JavaScript和本机移动应用程序,启动登录流程和接收可验证断言对登录用户的身份。

添加用户界面

在IdentityServer 项目下添加用户界面

.NET CLI(从src/IdentityServer文件夹内运行)

dotnet new is4ui

startup.cs您会发现ConfigureServicesConfigure方法中的注释告诉您如何启用 MVC

运行 IdentityServer 应用程序,看到如下页面

image-20211110152456988

AccountController是主要的UI入口点

创建MVC客户端

创建新的项目

从 src 文件夹运行:

dotnet new mvc -n MvcClient
cd ..
dotnet sln add .\src\MvcClient\MvcClient.csproj

我们建议通过 IIS Express 使用自托管选项。下面的文档是假设你在端口 5002 上使用自托管。

要向 MVC 应用程序添加对 OpenID Connect 身份验证的支持,您首先需要将包含 OpenID Connect 处理程序的 nuget 包添加到您的项目中,例如:

dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect -v 3.1

添加以下内容ConfigureServicesStartup

using System.IdentityModel.Tokens.Jwt;

// ...

JwtSecurityTokenHandler.DefaultMapInboundClaims = false;

services.AddAuthentication(options =>
    {
        options.DefaultScheme = "Cookies";
        options.DefaultChallengeScheme = "oidc";
    })
    .AddCookie("Cookies")
    .AddOpenIdConnect("oidc", options =>
    {
        options.Authority = "https://localhost:5001";

        options.ClientId = "mvc";
        options.ClientSecret = "secret";
        options.ResponseType = "code";

        options.SaveTokens = true;
    });

AddAuthentication 将身份验证服务添加到 DI。

我们使用 cookie 来本地登录用户(通过"Cookies"作为DefaultScheme),我们将 设置DefaultChallengeSchemeoidc因为当我们需要用户登录时,我们将使用 OpenID Connect 协议

然后我们使用AddCookie添加可以处理 cookie 的处理程序。

最后,AddOpenIdConnect用于配置执行 OpenID Connect 协议的处理程序。该Authority指示了信任令牌服务所在。然后,我们通过ClientId和识别此客户端ClientSecretSaveTokens用于将来自 IdentityServer 的令牌持久保存在 cookie 中(因为稍后将需要它们)。

为了确保对每个请求执行身份验证服务,添加UseAuthenticationStartupConfigure

app.UseStaticFiles();

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
    endpoints.MapDefaultControllerRoute()
        .RequireAuthorization();//禁用对整个应用程序的匿名访问
});

[Authorize]如果要在每个控制器或操作方法的基础上指定授权,也可以使用该属性。

还要修改主页视图以显示用户的声明以及 cookie 属性:

@using Microsoft.AspNetCore.Authentication

<h2>Claims</h2>

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

<h2>Properties</h2>

<dl>
    @foreach (var prop in (await Context.AuthenticateAsync()).Properties.Items)
    {
        <dt>@prop.Key</dt>
        <dd>@prop.Value</dd>
    }
</dl>

如果您现在使用浏览器导航到应用程序,则会尝试重定向到 IdentityServer - 这将导致错误,因为 MVC 客户端尚未注册。

image-20211111104809887

添加对 OpenID Connect 身份范围的支持

修改IdentityServer项目

与 OAuth 2.0 类似,OpenID Connect 也使用范围概念。同样,范围代表您想要保护和客户端想要访问的东西。与 OAuth 相比,OIDC 中的范围不代表 API,而是代表用户 ID、姓名或电子邮件地址等身份数据。

通过修改以下属性来添加对标准openid(主题 ID)和profile(名字、姓氏等)范围的支持:IdentityResources``Config.cs

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

向 IdentityServer 注册身份资源startup.cs

var builder = services.AddIdentityServer()
    .AddInMemoryIdentityResources(Config.IdentityResources)
    .AddInMemoryApiScopes(Config.ApiScopes)
    .AddInMemoryClients(Config.Clients);

添加测试用户

示例 UI 还带有一个内存中的“用户数据库”。您可以通过添加AddTestUsers扩展方法在 IdentityServer 中启用此功能:

var builder = services.AddIdentityServer()
    .AddInMemoryIdentityResources(Config.IdentityResources)
    .AddInMemoryApiScopes(Config.ApiScopes)
    .AddInMemoryClients(Config.Clients)
    .AddTestUsers(TestUsers.Users);

当您导航到TestUsers类,你可以看到两个用户名为alicebob以及一些身份声明定义。您可以使用这些用户登录。

将 MVC 客户端添加到 IdentityServer 配置

最后一步是将 MVC 客户端的新配置条目添加到 IdentityServer。

基于 OpenID Connect 的客户端与我们目前添加的 OAuth 2.0 客户端非常相似。但由于 OIDC 中的流始终是交互式的,我们需要在配置中添加一些重定向 URL。

客户列表应如下所示:

public static IEnumerable<Client> Clients =>
    new List<Client>
    {
        // machine to machine client (from quickstart 1)
        new Client
        {
            ClientId = "client",
            ClientSecrets = { new Secret("secret".Sha256()) },

            AllowedGrantTypes = GrantTypes.ClientCredentials,
            // scopes that client has access to
            AllowedScopes = { "api1" }
        },
        // interactive ASP.NET Core MVC client
        new Client
        {
            ClientId = "mvc",//授权时严格区分大小写
            ClientSecrets = { new Secret("secret".Sha256()) },

            AllowedGrantTypes = GrantTypes.Code,

            // where to redirect to after login
            RedirectUris = { "https://localhost:5002/signin-oidc" },

            // where to redirect to after logout
            PostLogoutRedirectUris = { "https://localhost:5002/signout-callback-oidc" },

            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile
            }
        }
    };

测试客户端

现在终于一切都应该为新的 MVC 客户端准备好了。

通过导航到受保护的控制器操作来触发身份验证握手。您应该会看到重定向到 IdentityServer 的登录页面。

image-20211111132032272

之后,IdentityServer 将重定向回 MVC 客户端,在那里 OpenID Connect 身份验证处理程序处理响应并通过设置 cookie 在本地登录用户。最后,MVC 视图将显示 cookie 的内容。

image-20211111133309368

如您所见,cookie 有两部分,用户的声明和一些元数据。此元数据还包含 IdentityServer 发布的原始令牌。随意将此令牌复制到jwt.ms以检查其内容。

添加注销

最后一步是向 MVC 客户端添加注销。

使用 IdentityServer 这样的身份验证服务,仅清除本地应用程序 cookie 是不够的。此外,您还需要往返 IdentityServer 以清除中央单点登录会话。

确切的协议步骤在 OpenID Connect 处理程序中实现,只需将以下代码添加到某个控制器以触发注销:

public IActionResult Logout()
{
    return SignOut("Cookies", "oidc");
}

这将清除本地 cookie,然后重定向到 IdentityServer。IdentityServer 将清除其 cookie,然后为用户提供一个链接以返回到 MVC 应用程序。

在_Layout.cshtml中添加Logout按钮

<li class="nav-item">
    <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Logout">Logout</a>
</li>

从 UserInfo 端点获取声明

您可能已经注意到,尽管我们已经配置的客户端被允许检索profile身份范围,与该范围相关联的债权(如namefamily_namewebsite等)不会出现在返回的标记。我们需要通过指定客户端应用程序需要访问的范围和设置选项来告诉客户端从UserInfo端点提取剩余的声明GetClaimsFromUserInfoEndpoint。在以下示例中,我们请求profile范围,但它可以是客户端有权访问的任何范围(或多个范围):

.AddOpenIdConnect("oidc", options =>
                  {
                      // ...
                      options.Scope.Add("profile");
                      options.GetClaimsFromUserInfoEndpoint = true;
                      // ...
                  });

重新启动客户端应用程序、注销并重新登录后,您应该会看到与profile页面上显示的身份范围关联的其他用户声明。

image-20211111140338769

进一步的实验

随意向测试用户添加更多声明 - 以及更多身份资源。

定义身份资源的过程如下:

  • 向列表中添加一个新的身份资源 - 为其命名并指定在请求此资源时应返回哪些声明

  • 通过AllowedScopes客户端配置上的属性授予客户端访问资源的权限

  • 通过将资源添加到Scopes客户端中 OpenID Connect 处理程序配置的集合来请求资源

  • (可选)如果身份资源与非标准声明(例如myclaim1)相关联,则在客户端添加以 JSON 形式出现的声明(从 UserInfo 端点返回)和用户声明之间的ClaimAction映射

    using Microsoft.AspNetCore.Authentication
    // ...
    .AddOpenIdConnect("oidc", options =>
    {
        // ...
        options.ClaimActions.MapUniqueJsonKey("myclaim1", "myclaim1");
        // ...
    });
    

同样值得注意的是,检索令牌声明是一个扩展点 - IProfileService。由于我们正在使用AddTestUsers,因此TestUserProfileService默认使用 。您可以在此处检查源代码 以了解其工作原理。

添加对外部身份验证的支持

接下来,我们将添加对外部身份验证的支持。这真的很简单,因为您真正需要的是一个与 ASP.NET Core 兼容的身份验证处理程序。

ASP.NET Core 本身支持 Google、Facebook、Twitter、Microsoft Account 和 OpenID Connect。此外,您可以在此处找到许多其他身份验证提供程序的实现。

添加 Google 支持

为了能够使用 Google 进行身份验证,您首先需要向他们注册。这是在他们的开发人员控制台上完成的。创建一个新项目,启用 Google+ API 并通过将/signin-google路径添加到您的基地址(例如https://localhost:5001/signin-google)来配置您本地 IdentityServer 的回调地址。

开发者控制台将向您显示由 Google 发布的客户端 ID 和机密 - 您将在下一步中用到它。

将 Google 身份验证处理程序添加到 IdentityServer 主机的 DI。这是通过首先添加Microsoft.AspNetCore.Authentication.Googlenuget 包然后将此代码段添加到ConfigureServicesin 来完成的Startup

services.AddAuthentication()
    .AddGoogle("Google", options =>
    {
        options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

        options.ClientId = "<insert here>";
        options.ClientSecret = "<insert here>";
    });

默认情况下,IdentityServer 专门为外部身份验证的结果配置 cookie 处理程序(使用基于常量的方案IdentityServerConstants.ExternalCookieAuthenticationScheme)。Google 处理程序的配置随后将使用该 cookie 处理程序。

现在运行 MVC 客户端并尝试进行身份验证 - 您将在登录页面上看到一个 Google 按钮:

image-20211111141042862

使用 MVC 客户端进行身份验证后,您可以看到声明现在来自 Google 数据。

进一步的实验

您可以添加额外的外部提供程序。我们有IdentityServer4的云托管演示版本,您可以使用 OpenID Connect 进行集成。

将 OpenId Connect 处理程序添加到 DI:

services.AddAuthentication()
    .AddGoogle("Google", options =>
    {
        options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;

        options.ClientId = "<insert here>";
        options.ClientSecret = "<insert here>";
    })
    .AddOpenIdConnect("oidc", "Demo IdentityServer", options =>
    {
        options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
        options.SignOutScheme = IdentityServerConstants.SignoutScheme;
        options.SaveTokens = true;

        options.Authority = "https://demo.identityserver.io/";
        options.ClientId = "interactive.confidential";
        options.ClientSecret = "secret";
        options.ResponseType = "code";

        options.TokenValidationParameters = new TokenValidationParameters
        {
            NameClaimType = "name",
            RoleClaimType = "role"
        };
    });

现在,用户应该能够使用云托管的演示身份提供程序。

快速入门 UI 自动配置外部用户。当外部用户第一次登录时,会创建一个新的本地用户,所有外部声明都被复制并与新用户关联。但是,您处理这种情况的方式完全取决于您。也许您想先显示某种注册 UI。可以在此处找到默认快速入门的源代码。可以在此处找到执行自动配置的控制器。

image-20211111141249765

posted @ 2021-11-10 17:48  CCmonitor  阅读(113)  评论(0)    收藏  举报