使用OpenID Connect添加用户认证

在本快速入门中,我们希望通过OpenID Connect协议为我们的IdentityServer添加对交互式用户身份验证的支持。

一旦到位,我们将创建一个将使用IdentityServer进行身份验证的MVC应用程序。

添加

OpenID Connect所需的所有协议支持已内置于IdentityServer中。您需要为登录,注销,同意和错误提供必要的UI部件。

虽然外观和精确的工作流程在每个IdentityServer实现中可能总是不同,但我们提供了一个基于MVC的示例UI,您可以将其用作起点。

可以在快速入门UI存储库中找到此UI 您可以克隆或下载此repo,并将控制器,视图,模型和CSS放入IdentityServer Web应用程序中。

或者,您可以从与IdentityServer Web应用程序相同的目录中的命令行运行此命令,以自动执行下载:

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

添加MVC UI资产后,您还需要在DI系统和管道中将MVC添加到托管应用程序。ConfigureServices使用AddMvc扩展方法添加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());
}

Configure使用UseMvc扩展方法将MVC添加为管道中的最后一个中间件

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

    app.UseIdentityServer();

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

有关详细信息,请参阅快速入门UI 自述文件

注意

releaseUI repo 分支具有与最新稳定版本匹配的UI。dev分支与IdentityServer4的当前开发版本一起使用。如果您正在寻找特定版本的UI - 请检查标签。

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

创建MVC客户端

接下来,您将向您的解决方案添加MVC应用程序。使用ASP.NET Core“Web应用程序”(即MVC)模板。不要在向导中配置“身份验证”设置 - 您将在此快速入门中手动执行此操作。创建项目后,将应用程序配置为使用端口5002(有关如何执行此操作的说明,请参阅概述部分)。

要为ID连接的认证支持添加到了MVC应用程序,添加以下内容ConfigureServicesStartup

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 "Cookies"DefaultScheme)。我们设置为DefaultChallengeSchemeto,"oidc"因为当我们需要用户登录时,我们将使用OpenID Connect方案。

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

最后,AddOpenIdConnect用于配置执行OpenID Connect协议的处理程序。Authority表明我们信任IdentityServer。然后我们通过ClientId识别这个客户。 SignInScheme用于在OpenID Connect协议完成后使用cookie处理程序发出cookie。并且SaveTokens用于在cookie中保留来自IdentityServer的令牌(因为稍后将需要它们)。

同样,我们已经关闭了JWT声明类型映射,以允许众所周知的声明(例如“sub”和“idp”)流畅地通过:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

然后要确保认证服务执行对每个请求,加入UseAuthenticationConfigureStartup

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

    app.UseAuthentication();

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

应该在管道中的MVC之前添加认证中间件。

最后一步是触发身份验证握手。为此,请转到主控制器并添加[Authorize]其中一个操作。同时修改该操作的视图以显示用户的声明,例如:

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

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

添加对OpenID Connect标识范围的支持

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

通过添加新助手(in )来创建对象集合,添加对标准openid(subject id)和profile(名字,姓氏等)范围的支持Config.csIdentityResource

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

注意

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

然后,您需要将这些标识资源添加到IdentityServer配置中Startup.cs使用AddInMemoryIdentityResources您调用扩展方法AddIdentityServer()

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隐式流添加客户端

最后一步是将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
            }
        }
    };
}

测试客户端

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

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

../_images/3_login.png

成功登录后,将向用户显示同意屏幕。在这里,用户可以决定是否要将他的身份信息发布到客户端应用程序。

注意

可以使用RequireConsent客户端对象上的属性基于每个客户端关闭同意

../_images/3_consent.png

..最后,浏览器重定向回客户端应用程序,显示用户的声明。

../_images/3_claims.png

注意

在开发期间,您有时可能会看到一个异常,指出无法验证令牌。这是因为签名密钥材料是在运行中创建的,并且仅保留在内存中。当客户端和IdentityServer不同步时会发生此异常。只需在客户端重复操作,下次元数据赶上时,一切都应该再次正常工作。

添加注销

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

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

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

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

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

进一步的实验

如上所述,OpenID Connect中间件默认要求配置文件范围。此范围还包括名称网站等声明

让我们将这些声明添加到用户,以便IdentityServer可以将它们放入身份标记:

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")
            }
        }
    };
}

下次进行身份验证时,您的声明页面现在会显示其他声明。

随意添加更多声明 - 以及更多范围。Scope对ID连接中间件属性可以在其中配置的作用域认证期间将发送到IdentityServer。

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

nidie.com.cn - 用心与你沟通