65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET Core:使用 IdentityServer 构建强大的身份验证和授权系统

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.11/5 (7投票s)

2020年10月5日

CPOL

5分钟阅读

viewsIcon

11329

使用 IdentityServer 和 ASP.NET Core 3.1 构建强大的身份验证和授权系统

OAuth 2.0 到底是什么?

OAuth 2.0 是一种授权协议,它允许用户授予第三方应用程序访问用户资源的权限,而无需透露用户的身份或凭证。需要注意的是,它是一个授权协议,只能用于授权场景,而不能用于身份验证流程。

Image for post

为什么使用 OpenID Connect?

OAuth 2.0 在解决授权问题方面非常出色,但我们需要一种解决方案来处理用户身份验证用例。聪明的人们聚集在一起,构建了一个高效的解决方案。OpenID Connect 是一个构建在 OAuth 2.0 框架之上的身份协议。

向 IdentityServer 问好!👋

IdentityServer 是一个用于 ASP.NET Core 的 OpenID Connect 和 OAuth 2.0 框架。IdentityServer 是 OpenID Connect 的官方认证实现。

根据 IdentityServer 的官方文档,它具有许多职责和功能

  • 保护您的资源
  • 使用本地账户存储或通过外部身份提供者对用户进行身份验证
  • 提供会话管理和单点登录
  • 管理和验证客户端
  • 向客户端颁发身份和访问令牌
  • 验证令牌

Hello World 程序

在本教程中,我们将构建一个中央身份验证系统,该系统将处理 MVC 和 Angular 应用程序访问受保护资源的身份验证请求。

Image for post

Hello World 程序

Image for post

MVC 应用

Image for post

Angular 应用

我们将使用 IdentityServer 设置一个中央身份验证系统。然后,我们将创建一个 MVC 应用程序,其受保护的页面可以在通过身份验证服务器进行身份验证后访问。我们还将创建一个 Angular 应用程序,该应用程序将能够在身份验证后访问受保护的 API。

设置中央身份验证系统所需的步骤 — 从 1000 英尺的视角

  • 创建 MVC ASP.NET Core 项目
  • 添加 IdentityServer NuGet 包
  • 添加 EF Core NuGet 包以存储客户端和配置
  • 在 Startup 中配置 IdentityServer 服务
  • 在中间件中添加 IdentityServer 管道
  • 在数据库中填充客户端和资源数据
  • 创建 AccountController 来处理注册和登录场景

从零开始设置身份验证服务器

  1. 创建一个空的 MVC .NET Core 项目。
  2. 添加所需的 NuGet 包。

    Image for post

    这些是我们设置 IdentityServerAspNetIdentity 以及用于持久化的 EF 所需的一些包。

  3. 让我们在 startup 文件中配置 IdentityServerAspNetIdentity 和 EF。

    Image for post

    让我们来理解一下我们在这里做了什么。首先,我们通过创建自己的 DbContext 配置了实体框架,然后我们使用相同的 DbContext 配置了 AspNetIdentity。最后,我们通过提供自定义的 ConfigurationDBContextPersistedGrantDbContext 来配置 IdentityServer。所有客户端和资源信息将通过这些上下文进行存储。

  4. 在中间件管道中,我们只需要添加一行代码来配置 IdentityServer 中间件。

    Image for post

    自定义 DbContext

    using AuthorizationServer.Models;
    using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    using Microsoft.EntityFrameworkCore;namespace AuthorizationServer.Persistence
    {
        public class AuthDbContext : IdentityDbContext<AppUser>
        {
            public AuthDbContext(DbContextOptions<AuthDbContext> options)
                : base(options)
            {
            }protected override void OnModelCreating(ModelBuilder builder)
            {
                base.OnModelCreating(builder);
                builder.HasDefaultSchema("Identity");
            }
        }
    }using IdentityServer4.EntityFramework.DbContexts;
    using IdentityServer4.EntityFramework.Options;
    using Microsoft.EntityFrameworkCore;namespace AuthorizationServer.Persistence
    {
        public class AuthConfigurationDbContext : 
                     ConfigurationDbContext<AuthConfigurationDbContext>
        {
            public AuthConfigurationDbContext
                   (DbContextOptions<AuthConfigurationDbContext> options, 
                   ConfigurationStoreOptions storeOptions) : base(options, storeOptions)
            {
            }protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
                modelBuilder.HasDefaultSchema("Identity");
            }
        }
    }using IdentityServer4.EntityFramework.DbContexts;
    using IdentityServer4.EntityFramework.Options;
    using Microsoft.EntityFrameworkCore;namespace AuthorizationServer.Persistence
    {
        public class AuthPersistedGrantDbContext : 
                     PersistedGrantDbContext<AuthPersistedGrantDbContext>
        {
            public AuthPersistedGrantDbContext
                   (DbContextOptions<AuthPersistedGrantDbContext> options, 
                   OperationalStoreOptions storeOptions) : base(options, storeOptions)
            {
            }protected override void OnModelCreating(ModelBuilder modelBuilder)
            {
                base.OnModelCreating(modelBuilder);
                modelBuilder.HasDefaultSchema("Identity");
            }
        }
    }

    没什么特别的,我们只是创建了自定义的 DbContext,以便我们可以拥有自定义的架构名称。

  5. 在所有 DbContext 连接好之后,我们可以创建一个 seed 类来填充我们的客户端和资源信息。我们可以将所有信息直接添加到数据库,也可以在应用程序启动时填充数据。

    Image for post

    我们需要客户端的信息,这些客户端将由 IdentityServer 进行身份验证,在我们的例子中,我们有两个客户端,一个是 MVC 应用,另一个是 Angular 应用。我们需要指定允许这些应用程序访问的资源。Angular 应用将需要访问 WeatherAPI 以及 OpenIdProfile。类似地,MVC 应用将需要访问 OpenIdProfile。我们需要将 WeatherAPI 添加为一个范围。客户端的 URL 是应用程序托管的 URL。

  6. 现在我们需要一个控制器和一个视图来管理用户的注册和登录。

    Image for post

    AccountController.cs

好了,我们的 AuthenticationServer 已准备好处理身份验证和授权请求。

构建 MVC 应用

假设我们有一个 MVC 应用,其页面是受保护的,只能在身份验证后访问。

我们需要配置其 startup 文件,使其了解 AuthenticationServerAuthentication 机制。

Image for post

Startup.cs

AddOpenIdConnect 方法接受选项,我们在其中指定 AuthenticationServer 的 URL、ClientIdClientSecretResponseTypeClientId 应与我们在身份验证服务器中配置的相同。

现在创建一个 home/secret 视图,并向其控制器/操作方法添加 [Authorize] 属性。之后,如果用户尝试访问 secret 视图,它将把请求重定向到身份验证服务器,在提供有效的用户名和密码后,用户将能够看到该页面。

设置 Angular 应用

对于 Angular 应用,我们需要一些后端 API,应用程序可以与之通信。然后,我们将在 API 中设置身份验证机制。经过身份验证的 Angular 应用会将 JWT 令牌发送到 API,然后 API 将验证该令牌和来自身份验证服务器的声明。

让我们在 API startup 文件中配置身份验证机制。

Image for post

Startup.cs

如果您仔细观察,我们会设置了身份验证服务器的 URL,并且还指定了我们在令牌中想要的声明/范围的名称。

对于我们的 Angular 应用,我们需要一个可靠的 npm 包来处理连接 Angular 应用和身份验证服务器所需的所有样板代码。

我们将 “angular-auth-oidc-client” 包添加到我们的应用中。

该包非常出色,因为它处理了我们的大部分工作,我们只需要编写一个配置函数,在该函数中指定身份验证服务器的 URL、我们想要的声明/范围以及一些重定向 URL。就这样,我们就绪了。

Image for post

identity.ts

Image for post

app.module.ts

让我们编写一些代码来登录用户,并在成功登录后,调用 API 获取数据,并将从身份验证服务器获得的令牌发送到标头中。

Image for post

app.component.ts

结束语

通过使用 IdentityServer,我们可以将身份验证/授权逻辑从我们的主应用程序中移出,使其更加松散耦合。IdentityServer 帮助我们创建一个中央身份验证系统。在微服务世界中,我们会创建一个中央身份验证系统,例如通过 IdentityServer 创建的系统。

我已在此处附上代码片段的屏幕截图,但您可以在 GitHub 上找到完整的源代码。

资源

😄 编码愉快!!

历史

  • 2020 年 10 月 5 日:初始版本
© . All rights reserved.