目录

OpenIddict基础使用

要使用 OpenIddict 实现自定义 OpenID Connect 服务器,最简单的选择是从openiddict-samples 存储库中克隆官方示例之一

如果您不想从推荐的示例之一开始,则需要:

  • 安装.NET Core 3.1(或更高版本)工具

  • 拥有现有项目或创建新项目:使用 Visual Studio 的默认 ASP.NET Core 模板创建新项目时,强烈建议使用个人用户帐户身份验证,因为它会自动包含基于 Razor Pages 的默认 ASP.NET Core Identity UI .

  • 更新您的.csproj文件以引用最新的OpenIddict软件包:

    <PackageReference Include="OpenIddict.AspNetCore" Version="3.1.1" />
    <PackageReference Include="OpenIddict.EntityFrameworkCore" Version="3.1.1" />
    
  • 配置OpenIddict 核心、服务器和验证服务Startup.ConfigureServices下面是客户端凭据授予的示例,用于机器对机器的场景:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();
    
        services.AddDbContext<ApplicationDbContext>(options =>
        {
            // Configure Entity Framework Core to use Microsoft SQL Server.
            options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
    
            // Register the entity sets needed by OpenIddict.
            // Note: use the generic overload if you need to replace the default OpenIddict entities.
            options.UseOpenIddict();
        });
    
        services.AddOpenIddict()
    
            // Register the OpenIddict core components.
            .AddCore(options =>
            {
                // Configure OpenIddict to use the Entity Framework Core stores and models.
                // Note: call ReplaceDefaultEntities() to replace the default entities.
                options.UseEntityFrameworkCore()
                       .UseDbContext<ApplicationDbContext>();
            })
    
            // Register the OpenIddict server components.
            .AddServer(options =>
            {
                // Enable the token endpoint.
                options.SetTokenEndpointUris("/connect/token");
    
                // Enable the client credentials flow.
                options.AllowClientCredentialsFlow();
    
                // Register the signing and encryption credentials.
                options.AddDevelopmentEncryptionCertificate()
                       .AddDevelopmentSigningCertificate();
    
                // Register the ASP.NET Core host and configure the ASP.NET Core options.
                options.UseAspNetCore()
                       .EnableTokenEndpointPassthrough();
            })
    
            // Register the OpenIddict validation components.
            .AddValidation(options =>
            {
                // Import the configuration from the local OpenIddict server instance.
                options.UseLocalServer();
    
                // Register the ASP.NET Core host.
                options.UseAspNetCore();
            });
    
        // Register the worker responsible of seeding the database with the sample clients.
        // Note: in a real world application, this step should be part of a setup script.
        services.AddHostedService<Worker>();
    }
    
  • 确保 ASP.NET Core 身份验证中间件在正确的位置正确注册

    public void Configure(IApplicationBuilder app)
    {
        app.UseDeveloperExceptionPage();
    
        app.UseRouting();
    
        app.UseAuthentication();
        app.UseAuthorization();
    
        app.UseEndpoints(options =>
        {
            options.MapControllers();
            options.MapDefaultControllerRoute();
        });
    }
    
  • 更新您的 Entity Framework Core 上下文注册以注册 OpenIddict 实体

    services.AddDbContext<ApplicationDbContext>(options =>
    {
        // Configure Entity Framework Core to use Microsoft SQL Server.
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
    
        // Register the entity sets needed by OpenIddict.
        // Note: use the generic overload if you need to replace the default OpenIddict entities.
        options.UseOpenIddict();
    });
    
    笔记

    默认情况下,OpenIddict Entity Framework Core 集成用string作主键的默认类型。要使用不同的类型,请阅读Entity Framework Core 集成:使用自定义主键类型

  • 创建您自己的授权控制器: 需要实现自定义授权控制器,以允许 OpenIddict 根据您提供的身份和声明创建令牌。以下是客户端凭据授予的示例:

    public class AuthorizationController : Controller
    {
        private readonly IOpenIddictApplicationManager _applicationManager;
    
        public AuthorizationController(IOpenIddictApplicationManager applicationManager)
            => _applicationManager = applicationManager;
    
        [HttpPost("~/connect/token"), Produces("application/json")]
        public async Task<IActionResult> Exchange()
        {
            var request = HttpContext.GetOpenIddictServerRequest();
            if (!request.IsClientCredentialsGrantType())
            {
                throw new NotImplementedException("The specified grant is not implemented.");
            }
    
            // Note: the client credentials are automatically validated by OpenIddict:
            // if client_id or client_secret are invalid, this action won't be invoked.
    
            var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ??
                throw new InvalidOperationException("The application cannot be found.");
    
            // Create a new ClaimsIdentity containing the claims that
            // will be used to create an id_token, a token or a code.
            var identity = new ClaimsIdentity(TokenValidationParameters.DefaultAuthenticationType, Claims.Name, Claims.Role);
    
            // Use the client_id as the subject identifier.
            identity.AddClaim(Claims.Subject,
                await _applicationManager.GetClientIdAsync(application),
                Destinations.AccessToken, Destinations.IdentityToken);
    
            identity.AddClaim(Claims.Name,
                await _applicationManager.GetDisplayNameAsync(application),
                Destinations.AccessToken, Destinations.IdentityToken);
    
            return SignIn(new ClaimsPrincipal(identity), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);
        }
    }
    
  • 注册您的客户端应用程序(例如从IHostedService实现):

    public class Worker : IHostedService
    {
        private readonly IServiceProvider _serviceProvider;
    
        public Worker(IServiceProvider serviceProvider)
            => _serviceProvider = serviceProvider;
    
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            using var scope = _serviceProvider.CreateScope();
    
            var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
            await context.Database.EnsureCreatedAsync();
    
            var manager = scope.ServiceProvider.GetRequiredService<IOpenIddictApplicationManager>();
    
            if (await manager.FindByClientIdAsync("console") is null)
            {
                await manager.CreateAsync(new OpenIddictApplicationDescriptor
                {
                    ClientId = "console",
                    ClientSecret = "388D45FA-B36B-4988-BA59-B187D329C207",
                    DisplayName = "My client application",
                    Permissions =
                    {
                        Permissions.Endpoints.Token,
                        Permissions.GrantTypes.ClientCredentials
                    }
                });
            }
        }
    
        public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
    }
    

    Add-Migration在运行应用程序之前,请确保通过运行和来使用 OpenIddict 表更新数据库Update-Database