OpenIddict基础使用
要使用 OpenIddict 实现自定义 OpenID Connect 服务器,最简单的选择是从openiddict-samples 存储库中克隆官方示例之一。
如果您不想从推荐的示例之一开始,则需要:
拥有现有项目或创建新项目:使用 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
。