using System; using System.Threading.Tasks; using AspNet.Security.OpenIdConnect.Primitives; 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 = OpenIdConnectConstants.Claims.Name; options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject; options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role; }); services.AddAuthentication() .AddGoogle(options => { options.ClientId = "560027070069-37ldt4kfuohhu3m495hk2j4pjp92d382.apps.googleusercontent.com"; options.ClientSecret = "n2Q-GEw9RQjzcRbU3qhfTj8f"; }) .AddTwitter(options => { options.ConsumerKey = "6XaCTaLbMqfj6ww3zvZ5g"; options.ConsumerSecret = "Il2eFzGIrYhz6BWjYhVXBPQSfZuS4xoHpSSyD9PI"; }); 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 => { // Register the ASP.NET Core MVC services used by OpenIddict. // Note: if you don't call this method, you won't be able to // bind OpenIdConnectRequest or OpenIdConnectResponse parameters. options.UseMvc(); // Enable the authorization, logout, token and userinfo endpoints. options.EnableAuthorizationEndpoint("/connect/authorize") .EnableLogoutEndpoint("/connect/logout") .EnableTokenEndpoint("/connect/token") .EnableUserinfoEndpoint("/api/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(OpenIdConnectConstants.Scopes.Email, OpenIdConnectConstants.Scopes.Profile, OpenIddictConstants.Scopes.Roles); // When request caching is enabled, authorization and logout requests // are stored in the distributed cache by OpenIddict and the user agent // is redirected to the same page with a single parameter (request_id). // This allows flowing large OpenID Connect requests even when using // an external authentication provider like Google, Facebook or Twitter. options.EnableRequestCaching(); // During development, you can disable the HTTPS requirement. options.DisableHttpsRequirement(); // Note: to use JWT access tokens instead of the default // encrypted format, the following lines are required: // // options.UseJsonWebTokens(); // options.AddEphemeralSigningKey(); // 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(); }) // Register the OpenIddict validation handler. // Note: the OpenIddict validation handler is only compatible with the // default token format or with reference tokens and cannot be used with // JWT tokens. For JWT tokens, use the Microsoft JWT bearer handler. .AddValidation(); services.AddTransient(); services.AddTransient(); } public void Configure(IApplicationBuilder app) { app.UseDeveloperExceptionPage(); app.UseStaticFiles(); app.UseStatusCodePagesWithReExecute("/error"); app.UseAuthentication(); app.UseMvcWithDefaultRoute(); // 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.Scopes.Email, OpenIddictConstants.Permissions.Scopes.Profile, OpenIddictConstants.Permissions.Scopes.Roles } }; await manager.CreateAsync(descriptor); } } } } }