IdentityServer4 学习笔记-用户身份验证

373 阅读5分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情

通过OpenID Connect协议向我们的IdentityServer添加对交互式用户身份验证的支持。
一旦成功,将创建一个将使用IdentityServer进行身份验证的MVC应用程序。

1.添加

IdentityServer 内置了 OpenID Connect 需要的所有协议支持。需要提供必需的 UI 部分,包括 登录、注销、授权确认以及错误页。 因为在每个 IdentityServer 的实现中,视觉、感觉以及实际工作流可能总是有所不同的,所以提供了一套基于 MVC 的样例 UI,可以将其作为启动点来使用。

这套 UI 可以在仓库 找到。还可以克隆或下载这个仓库,将其中的控制器、视图、模型以及 CSS 放到自己的 Web 应用程序中。 或者,可以使用.NET CLI(从src/IdentityServer文件夹中运行):

dotnet new is4ui

添加MVC UI后,还需要在DI系统和管道中启用MVC。当查看时,*Startup.cs*在ConfigureServicesConfigure`方法中找到注释,指示如何启用MVC。

运行IdentityServer应用程序,现在应该看到一个主页。

花一些时间检查控制器和模型,就越容易进行未来的修改。大多数代码使用“feature folder”样式存在于“Quickstart”文件夹中。如果此样式不适合,可以随意以想要的任何方式组织代码。

2.创建MVC客户端

接下来,将向解决方案添加MVC应用程序。使用ASP.NET Core“Web应用程序”(即MVC)模板。不要在向导中配置“身份验证”设置 - 手动执行操作。创建项目后,将应用程序配置为在端口8080上运行。

要为OpenID Connect的认证支持添加到MVC应用程序,添加以下内容到StartupConfigureServices

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.Authority = "http://localhost:5000";
            options.RequireHttpsMetadata = false;

            options.ClientId = "mvc";
            options.SaveTokens = true;
        });
}

AddAuthentication将身份验证服务添加到DI。我们使用cookie来本地登录用户(通过"Cookies"作为DefaultScheme),我们设置为DefaultChallengeScheme"oidc"因为当我们需要用户登录时,我们将使用OpenID Connect协议。

然后AddCookie,我们添加可处理cookie的处理程序。

最后,AddOpenIdConnect用于配置执行OpenID Connect协议的处理程序。Authority表明信任IdentityServer。然后通过ClientId。识别这个客户。 SaveTokens用于在cookie中保留来自IdentityServer的令牌(后面会用到)。

同样,已经关闭了JWT声明类型映射,以允许声明(例如'sub'和'idp')流畅地通过:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

要确保认证服务执行对每个请求,加入UseAuthenticationStartupConfigure,应该在管道中的MVC之前添加认证中间件。

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseAuthentication();

    app.UseStaticFiles();
    app.UseMvcWithDefaultRoute();
}

最后一步是触发身份验证握手。为此,到主控制器并添加[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客户端还没有注册。

3.对OpenID Connect的支持

与OAuth 2.0类似,OpenID Connect也使用范围(Scope)概念。同样,范围代表想要保护的内容以及客户想要访问的内容。与OAuth相比,OIDC中的范围不代表API,而是代表用户ID,名称或电子邮件地址等身份数据。
通过修改方法,添加对标准openid(subject id)和profile(名字,姓氏等)范围(Scope)的支持Config.csGetIdentityResources

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

所有标准范围及其相应的声明都可以在OpenID Connect规范中找到

4.OpenID Connect添加客户端

最后一步是将MVC客户端的新配置条目添加到IdentityServer。
基于OpenID Connect的客户端与我们目前添加的OAuth 2.0客户端非常相似。但由于OIDC中的流程始终是交互式的,因此需要在配置中添加一些重定向URL。
将以下内容添加到客户端配置中:

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
            }
        }
    };
}
5.测试客户端

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

登录成功后,用户将在授权确认页中被呈现出来。在这里用户可以决定他是否想要发布他的身份信息给客户端应用程序。 授权确认页可以通过客户端定义对象的`RequireConsent`属性被关闭(以每个客户端为单位)。

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

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

6.注销客户端

最后一步是向MVC客户端添加注销。
使用IdentityServer等身份验证服务,仅清除本地应用程序cookie是不够的。此外,还需要向IdentityServer进行往返以清除中央单点登录会话。
确切的协议步骤在OpenID Connect处理程序中实现,只需将以下代码添加到某个控制器即可触发注销:

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

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