using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Identity; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Mvc.Server.Models; using Mvc.Server.Services; using OpenIddict.Abstractions; using OpenIddict.Core; using OpenIddict.EntityFrameworkCore.Models; namespace Mvc.Server { public class Startup { public Startup(IConfiguration configuration) => Configuration = configuration; public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddDbContext(options => { // Configure the context 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(); }); // Register the Identity services. services.AddIdentity() .AddEntityFrameworkStores() .AddDefaultTokenProviders(); // Configure Identity to use the same JWT claims as OpenIddict instead // of the legacy WS-Federation claims it uses by default (ClaimTypes), // which saves you from doing the mapping in your authorization controller. services.Configure(options => { options.ClaimsIdentity.UserNameClaimType = OpenIddictConstants.Claims.Name; options.ClaimsIdentity.UserIdClaimType = OpenIddictConstants.Claims.Subject; options.ClaimsIdentity.RoleClaimType = OpenIddictConstants.Claims.Role; }); services.AddOpenIddict() // Register the OpenIddict core services. .AddCore(options => { // Configure OpenIddict to use the Entity Framework Core stores and models. options.UseEntityFrameworkCore() .UseDbContext(); }) // Register the OpenIddict server handler. .AddServer(options => { // Enable the authorization, logout, token and userinfo endpoints. options.SetAuthorizationEndpointUris("/connect/authorize") .SetLogoutEndpointUris("/connect/logout") .SetTokenEndpointUris("/connect/token") .SetUserinfoEndpointUris("/connect/userinfo"); // Note: the Mvc.Client sample only uses the code flow and the password flow, but you // can enable the other flows if you need to support implicit or client credentials. options.AllowAuthorizationCodeFlow() .AllowPasswordFlow() .AllowRefreshTokenFlow(); // Mark the "email", "profile" and "roles" scopes as supported scopes. options.RegisterScopes(OpenIddictConstants.Scopes.Email, OpenIddictConstants.Scopes.Profile, OpenIddictConstants.Scopes.Roles); // Register the signing and encryption credentials. options.AddDevelopmentEncryptionCertificate() .AddDevelopmentSigningCertificate(); // Register the ASP.NET Core host and configure the ASP.NET Core-specific options. options.UseAspNetCore() .EnableStatusCodePagesIntegration() .EnableAuthorizationEndpointPassthrough() .EnableLogoutEndpointPassthrough() .EnableTokenEndpointPassthrough() .EnableUserinfoEndpointPassthrough() .DisableTransportSecurityRequirement(); // During development, you can disable the HTTPS requirement. // Note: if you don't want to specify a client_id when sending // a token or revocation request, uncomment the following line: // // options.AcceptAnonymousClients(); // Note: if you want to process authorization and token requests // that specify non-registered scopes, uncomment the following line: // // options.DisableScopeValidation(); // Note: if you don't want to use permissions, you can disable // permission enforcement by uncommenting the following lines: // // options.IgnoreEndpointPermissions() // .IgnoreGrantTypePermissions() // .IgnoreScopePermissions(); }); services.AddTransient(); services.AddTransient(); } public void Configure(IApplicationBuilder app) { app.UseDeveloperExceptionPage(); app.UseStaticFiles(); app.UseStatusCodePagesWithReExecute("/error"); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(options => options.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}")); // Seed the database with the sample applications. // Note: in a real world application, this step should be part of a setup script. InitializeAsync(app.ApplicationServices).GetAwaiter().GetResult(); } private async Task InitializeAsync(IServiceProvider services) { // Create a new service scope to ensure the database context is correctly disposed when this methods returns. using var scope = services.GetRequiredService().CreateScope(); var context = scope.ServiceProvider.GetRequiredService(); await context.Database.EnsureCreatedAsync(); var manager = scope.ServiceProvider.GetRequiredService>(); if (await manager.FindByClientIdAsync("mvc") == null) { var descriptor = new OpenIddictApplicationDescriptor { ClientId = "mvc", ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654", DisplayName = "MVC client application", PostLogoutRedirectUris = { new Uri("http://localhost:53507/signout-callback-oidc") }, RedirectUris = { new Uri("http://localhost:53507/signin-oidc") }, Permissions = { OpenIddictConstants.Permissions.Endpoints.Authorization, OpenIddictConstants.Permissions.Endpoints.Logout, OpenIddictConstants.Permissions.Endpoints.Token, OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, OpenIddictConstants.Permissions.GrantTypes.RefreshToken, OpenIddictConstants.Permissions.Scopes.Email, OpenIddictConstants.Permissions.Scopes.Profile, OpenIddictConstants.Permissions.Scopes.Roles } }; await manager.CreateAsync(descriptor); } // To test this sample with Postman, use the following settings: // // * Authorization URL: http://localhost:54540/connect/authorize // * Access token URL: http://localhost:54540/connect/token // * Client ID: postman // * Client secret: [blank] (not used with public clients) // * Scope: openid email profile roles // * Grant type: authorization code // * Request access token locally: yes if (await manager.FindByClientIdAsync("postman") == null) { var descriptor = new OpenIddictApplicationDescriptor { ClientId = "postman", DisplayName = "Postman", RedirectUris = { new Uri("https://www.getpostman.com/oauth2/callback") }, Permissions = { OpenIddictConstants.Permissions.Endpoints.Authorization, OpenIddictConstants.Permissions.Endpoints.Token, OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, OpenIddictConstants.Permissions.GrantTypes.Password, OpenIddictConstants.Permissions.Scopes.Email, OpenIddictConstants.Permissions.Scopes.Profile, OpenIddictConstants.Permissions.Scopes.Roles } }; await manager.CreateAsync(descriptor); } } } }