├── .gitignore ├── Angular-Core-IdentityServer.sln ├── ApiApp ├── ApiApp.csproj ├── Controllers │ ├── IdentityController.cs │ ├── SampleDataController.cs │ └── ValuesController.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── appsettings.Development.json └── appsettings.json ├── ClientApp ├── .gitignore ├── ClientApp.csproj ├── ClientApp │ ├── .angular-cli.json │ ├── .editorconfig │ ├── .gitignore │ ├── README.md │ ├── e2e │ │ ├── app.e2e-spec.ts │ │ ├── app.po.ts │ │ └── tsconfig.e2e.json │ ├── karma.conf.js │ ├── package-lock.json │ ├── package.json │ ├── protractor.conf.js │ ├── src │ │ ├── app │ │ │ ├── app.component.css │ │ │ ├── app.component.html │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── configuration │ │ │ │ └── configuration.service.ts │ │ │ ├── counter │ │ │ │ ├── counter.component.html │ │ │ │ ├── counter.component.spec.ts │ │ │ │ └── counter.component.ts │ │ │ ├── fetch-data │ │ │ │ ├── fetch-data.component.html │ │ │ │ └── fetch-data.component.ts │ │ │ ├── home │ │ │ │ ├── home.component.html │ │ │ │ └── home.component.ts │ │ │ ├── nav-menu │ │ │ │ ├── nav-menu.component.css │ │ │ │ ├── nav-menu.component.html │ │ │ │ └── nav-menu.component.ts │ │ │ ├── services │ │ │ │ └── auth.service.ts │ │ │ └── unauthorized │ │ │ │ ├── unauthorized.component.html │ │ │ │ └── unauthorized.component.ts │ │ ├── assets │ │ │ └── .gitkeep │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.css │ │ ├── test.ts │ │ ├── tsconfig.app.json │ │ ├── tsconfig.spec.json │ │ └── typings.d.ts │ ├── tsconfig.json │ └── tslint.json ├── Controllers │ ├── ConfigurationController.cs │ ├── IdentityController.cs │ └── SampleDataController.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Startup.cs ├── Views │ ├── Identity │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── appsettings.Development.json ├── appsettings.json └── wwwroot │ └── favicon.ico ├── IdentityApp ├── .bowerrc ├── Config.cs ├── Controllers │ ├── AccountController.cs │ ├── HomeController.cs │ └── ManageController.cs ├── Data │ ├── ApplicationDbContext.cs │ └── Migrations │ │ ├── 20171007184832_InitApplication.Designer.cs │ │ ├── 20171007184832_InitApplication.cs │ │ ├── ApplicationDbContextModelSnapshot.cs │ │ └── IdentityServer │ │ ├── Configuration │ │ ├── 20171007184739_InitConfigration.Designer.cs │ │ ├── 20171007184739_InitConfigration.cs │ │ ├── 20180109123644_Configration21.Designer.cs │ │ ├── 20180109123644_Configration21.cs │ │ ├── 20181213121939_IDPackageUpdateDec2018Config.Designer.cs │ │ ├── 20181213121939_IDPackageUpdateDec2018Config.cs │ │ └── ConfigurationDbContextModelSnapshot.cs │ │ ├── IdentityServerDatabaseInitialization.cs │ │ └── PersistedGrant │ │ ├── 20171007184807_InitPersistedGrant.Designer.cs │ │ ├── 20171007184807_InitPersistedGrant.cs │ │ ├── 20180109123811_PersistedGrant21.Designer.cs │ │ ├── 20180109123811_PersistedGrant21.cs │ │ ├── 20181213122026_IDPackageUpdateDec2018Persited.Designer.cs │ │ ├── 20181213122026_IDPackageUpdateDec2018Persited.cs │ │ └── PersistedGrantDbContextModelSnapshot.cs ├── Extensions │ ├── EmailSenderExtensions.cs │ └── UrlHelperExtensions.cs ├── IdentityApp.csproj ├── Models │ ├── AccountViewModels │ │ ├── ExternalLoginViewModel.cs │ │ ├── ForgotPasswordViewModel.cs │ │ ├── LoginViewModel.cs │ │ ├── LoginWith2faViewModel.cs │ │ ├── LoginWithRecoveryCodeViewModel.cs │ │ ├── RegisterViewModel.cs │ │ └── ResetPasswordViewModel.cs │ ├── ApplicationUser.cs │ └── ManageViewModels │ │ ├── ChangePasswordViewModel.cs │ │ ├── EnableAuthenticatorViewModel.cs │ │ ├── ExternalLoginsViewModel.cs │ │ ├── GenerateRecoveryCodesViewModel.cs │ │ ├── IndexViewModel.cs │ │ ├── RemoveLoginViewModel.cs │ │ ├── SetPasswordViewModel.cs │ │ └── TwoFactorAuthenticationViewModel.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── Quickstart │ ├── Account │ │ ├── AccountOptions.cs │ │ ├── AccountService.cs │ │ ├── LoggedOutViewModel.cs │ │ ├── LogoutInputModel.cs │ │ └── LogoutViewModel.cs │ ├── Consent │ │ ├── ConsentController.cs │ │ ├── ConsentInputModel.cs │ │ ├── ConsentOptions.cs │ │ ├── ConsentService.cs │ │ ├── ConsentViewModel.cs │ │ ├── ProcessConsentResult.cs │ │ └── ScopeViewModel.cs │ ├── Grants │ │ ├── GrantsController.cs │ │ └── GrantsViewModel.cs │ ├── Home │ │ └── ErrorViewModel.cs │ └── SecurityHeadersAttribute.cs ├── Services │ ├── EmailSender.cs │ ├── IEmailSender.cs │ ├── ISmsSender.cs │ └── MessageServices.cs ├── Startup.cs ├── Views │ ├── Account │ │ ├── AccessDenied.cshtml │ │ ├── ConfirmEmail.cshtml │ │ ├── ExternalLogin.cshtml │ │ ├── ForgotPassword.cshtml │ │ ├── ForgotPasswordConfirmation.cshtml │ │ ├── Lockout.cshtml │ │ ├── LoggedOut.cshtml │ │ ├── Login.cshtml │ │ ├── LoginWith2fa.cshtml │ │ ├── LoginWithRecoveryCode.cshtml │ │ ├── Logout.cshtml │ │ ├── Register.cshtml │ │ ├── ResetPassword.cshtml │ │ ├── ResetPasswordConfirmation.cshtml │ │ └── SignedOut.cshtml │ ├── Consent │ │ ├── Index.cshtml │ │ └── _ScopeListItem.cshtml │ ├── Grants │ │ └── Index.cshtml │ ├── Home │ │ ├── About.cshtml │ │ ├── Contact.cshtml │ │ └── Index.cshtml │ ├── Manage │ │ ├── ChangePassword.cshtml │ │ ├── Disable2fa.cshtml │ │ ├── EnableAuthenticator.cshtml │ │ ├── ExternalLogins.cshtml │ │ ├── GenerateRecoveryCodes.cshtml │ │ ├── Index.cshtml │ │ ├── ManageNavPages.cs │ │ ├── ResetAuthenticator.cshtml │ │ ├── SetPassword.cshtml │ │ ├── TwoFactorAuthentication.cshtml │ │ ├── _Layout.cshtml │ │ ├── _ManageNav.cshtml │ │ ├── _StatusMessage.cshtml │ │ └── _ViewImports.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ ├── _Layout.cshtml │ │ ├── _LoginPartial.cshtml │ │ ├── _ValidationScriptsPartial.cshtml │ │ └── _ValidationSummary.cshtml │ ├── _ViewImports.cshtml │ └── _ViewStart.cshtml ├── appsettings.Development.json ├── appsettings.json ├── bower.json ├── bundleconfig.json ├── tempkey.rsa └── wwwroot │ ├── _references.js │ ├── css │ ├── site.css │ └── site.min.css │ ├── favicon.ico │ ├── icon.jpg │ ├── icon.png │ ├── images │ ├── banner1.svg │ ├── banner2.svg │ ├── banner3.svg │ └── banner4.svg │ ├── js │ ├── signout-redirect.js │ ├── site.js │ └── site.min.js │ └── lib │ ├── bootstrap │ ├── .bower.json │ ├── LICENSE │ ├── css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── dist │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.css.map │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap-theme.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ └── npm.js │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ └── js │ │ ├── bootstrap.js │ │ └── bootstrap.min.js │ ├── jquery-validation-unobtrusive │ ├── .bower.json │ ├── jquery.validate.unobtrusive.js │ └── jquery.validate.unobtrusive.min.js │ ├── jquery-validation │ ├── .bower.json │ ├── LICENSE.md │ └── dist │ │ ├── additional-methods.js │ │ ├── additional-methods.min.js │ │ ├── jquery.validate.js │ │ └── jquery.validate.min.js │ └── jquery │ ├── .bower.json │ ├── LICENSE.txt │ ├── dist │ ├── jquery.js │ ├── jquery.min.js │ └── jquery.min.map │ ├── jquery.js │ ├── jquery.min.js │ └── jquery.min.map ├── LICENSE └── README.md /Angular-Core-IdentityServer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.13 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApiApp", "ApiApp\ApiApp.csproj", "{454C2629-032B-4EE3-AD7E-2B08A16C264D}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ClientApp", "ClientApp\ClientApp.csproj", "{3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IdentityApp", "IdentityApp\IdentityApp.csproj", "{4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Debug|x64 = Debug|x64 16 | Debug|x86 = Debug|x86 17 | Release|Any CPU = Release|Any CPU 18 | Release|x64 = Release|x64 19 | Release|x86 = Release|x86 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Debug|x64.ActiveCfg = Debug|Any CPU 25 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Debug|x64.Build.0 = Debug|Any CPU 26 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Debug|x86.ActiveCfg = Debug|Any CPU 27 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Debug|x86.Build.0 = Debug|Any CPU 28 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Release|x64.ActiveCfg = Release|Any CPU 31 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Release|x64.Build.0 = Release|Any CPU 32 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Release|x86.ActiveCfg = Release|Any CPU 33 | {454C2629-032B-4EE3-AD7E-2B08A16C264D}.Release|x86.Build.0 = Release|Any CPU 34 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Debug|x64.ActiveCfg = Debug|Any CPU 37 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Debug|x64.Build.0 = Debug|Any CPU 38 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Debug|x86.ActiveCfg = Debug|Any CPU 39 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Debug|x86.Build.0 = Debug|Any CPU 40 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Release|x64.ActiveCfg = Release|Any CPU 43 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Release|x64.Build.0 = Release|Any CPU 44 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Release|x86.ActiveCfg = Release|Any CPU 45 | {3B48DD57-2BB6-4C48-BD05-5778F26FCE9C}.Release|x86.Build.0 = Release|Any CPU 46 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Debug|x64.ActiveCfg = Debug|Any CPU 49 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Debug|x64.Build.0 = Debug|Any CPU 50 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Debug|x86.ActiveCfg = Debug|Any CPU 51 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Debug|x86.Build.0 = Debug|Any CPU 52 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Release|Any CPU.ActiveCfg = Release|Any CPU 53 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Release|Any CPU.Build.0 = Release|Any CPU 54 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Release|x64.ActiveCfg = Release|Any CPU 55 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Release|x64.Build.0 = Release|Any CPU 56 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Release|x86.ActiveCfg = Release|Any CPU 57 | {4D95FBB9-C49B-4D19-86EF-9F3E67382A3D}.Release|x86.Build.0 = Release|Any CPU 58 | EndGlobalSection 59 | GlobalSection(SolutionProperties) = preSolution 60 | HideSolutionNode = FALSE 61 | EndGlobalSection 62 | EndGlobal 63 | -------------------------------------------------------------------------------- /ApiApp/ApiApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.2 5 | InProcess 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /ApiApp/Controllers/IdentityController.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.AspNetCore.Authorization; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace ApiApp.Controllers 6 | { 7 | [Route("api/[controller]")] 8 | [Authorize] 9 | public class IdentityController : Controller 10 | { 11 | [HttpGet] 12 | public IActionResult Get() 13 | { 14 | return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ApiApp/Controllers/SampleDataController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Microsoft.AspNetCore.Authorization; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace WebApplicationBasic.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | [Authorize] 11 | public class SampleDataController : Controller 12 | { 13 | private static string[] Summaries = new[] 14 | { 15 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 16 | }; 17 | 18 | [HttpGet("[action]")] 19 | public IEnumerable WeatherForecasts() 20 | { 21 | var rng = new Random(); 22 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 23 | { 24 | DateFormatted = DateTime.Now.AddDays(index).ToString("d"), 25 | TemperatureC = rng.Next(-20, 55), 26 | Summary = Summaries[rng.Next(Summaries.Length)] 27 | }); 28 | } 29 | 30 | public class WeatherForecast 31 | { 32 | public string DateFormatted { get; set; } 33 | public int TemperatureC { get; set; } 34 | public string Summary { get; set; } 35 | 36 | public int TemperatureF 37 | { 38 | get 39 | { 40 | return 32 + (int)(TemperatureC / 0.5556); 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /ApiApp/Controllers/ValuesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace ApiApp.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | public class ValuesController : Controller 11 | { 12 | // GET api/values 13 | [HttpGet] 14 | public IEnumerable Get() 15 | { 16 | return new string[] { "value1", "value2" }; 17 | } 18 | 19 | // GET api/values/5 20 | [HttpGet("{id}")] 21 | public string Get(int id) 22 | { 23 | return "value"; 24 | } 25 | 26 | // POST api/values 27 | [HttpPost] 28 | public void Post([FromBody]string value) 29 | { 30 | } 31 | 32 | // PUT api/values/5 33 | [HttpPut("{id}")] 34 | public void Put(int id, [FromBody]string value) 35 | { 36 | } 37 | 38 | // DELETE api/values/5 39 | [HttpDelete("{id}")] 40 | public void Delete(int id) 41 | { 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ApiApp/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | 4 | namespace ApiApp 5 | { 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | { 10 | CreateWebHostBuilder(args).Build().Run(); 11 | } 12 | 13 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 14 | WebHost.CreateDefaultBuilder(args) 15 | .UseStartup(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /ApiApp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:5001/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "environmentVariables": { 14 | "ASPNETCORE_ENVIRONMENT": "Development" 15 | } 16 | }, 17 | "ApiApp": { 18 | "commandName": "Project", 19 | "applicationUrl": "http://localhost:5001" 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /ApiApp/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication.JwtBearer; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace ApiApp 9 | { 10 | public class Startup 11 | { 12 | public IConfiguration Configuration { get; } 13 | 14 | public Startup(IConfiguration configuration) 15 | { 16 | Configuration = configuration; 17 | } 18 | 19 | 20 | public void ConfigureServices(IServiceCollection services) 21 | { 22 | services.AddAuthentication(options => 23 | { 24 | options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 25 | options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; 26 | }).AddJwtBearer(o => 27 | { 28 | o.Authority = Configuration["IdentityServerAddress"]; 29 | o.Audience = "apiApp"; 30 | o.RequireHttpsMetadata = false; 31 | }); 32 | 33 | services.AddCors(options => 34 | { 35 | options.AddPolicy("default", policy => 36 | { 37 | policy.WithOrigins(Configuration["ClientAddress"]) 38 | .AllowAnyHeader() 39 | .AllowAnyMethod(); 40 | }); 41 | }); 42 | 43 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 44 | } 45 | 46 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 47 | { 48 | 49 | app.UseCors("default"); 50 | 51 | app.UseAuthentication(); 52 | 53 | app.UseMvc(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /ApiApp/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /ApiApp/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Warning" 6 | } 7 | }, 8 | "IdentityServerAddress": "http://localhost:5000", 9 | "ClientAddress": "http://localhost:5002" 10 | } 11 | -------------------------------------------------------------------------------- /ClientApp/.gitignore: -------------------------------------------------------------------------------- 1 | /Properties/launchSettings.json 2 | 3 | ## Ignore Visual Studio temporary files, build results, and 4 | ## files generated by popular Visual Studio add-ons. 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | build/ 23 | bld/ 24 | bin/ 25 | Bin/ 26 | obj/ 27 | Obj/ 28 | 29 | # Visual Studio 2015 cache/options directory 30 | .vs/ 31 | 32 | # MSTest test Results 33 | [Tt]est[Rr]esult*/ 34 | [Bb]uild[Ll]og.* 35 | 36 | # NUNIT 37 | *.VisualState.xml 38 | TestResult.xml 39 | 40 | # Build Results of an ATL Project 41 | [Dd]ebugPS/ 42 | [Rr]eleasePS/ 43 | dlldata.c 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opendb 78 | *.opensdf 79 | *.sdf 80 | *.cachefile 81 | 82 | # Visual Studio profiler 83 | *.psess 84 | *.vsp 85 | *.vspx 86 | *.sap 87 | 88 | # TFS 2012 Local Workspace 89 | $tf/ 90 | 91 | # Guidance Automation Toolkit 92 | *.gpState 93 | 94 | # ReSharper is a .NET coding add-in 95 | _ReSharper*/ 96 | *.[Rr]e[Ss]harper 97 | *.DotSettings.user 98 | 99 | # JustCode is a .NET coding add-in 100 | .JustCode 101 | 102 | # TeamCity is a build add-in 103 | _TeamCity* 104 | 105 | # DotCover is a Code Coverage Tool 106 | *.dotCover 107 | 108 | # NCrunch 109 | _NCrunch_* 110 | .*crunch*.local.xml 111 | nCrunchTemp_* 112 | 113 | # MightyMoose 114 | *.mm.* 115 | AutoTest.Net/ 116 | 117 | # Web workbench (sass) 118 | .sass-cache/ 119 | 120 | # Installshield output folder 121 | [Ee]xpress/ 122 | 123 | # DocProject is a documentation generator add-in 124 | DocProject/buildhelp/ 125 | DocProject/Help/*.HxT 126 | DocProject/Help/*.HxC 127 | DocProject/Help/*.hhc 128 | DocProject/Help/*.hhk 129 | DocProject/Help/*.hhp 130 | DocProject/Help/Html2 131 | DocProject/Help/html 132 | 133 | # Click-Once directory 134 | publish/ 135 | 136 | # Publish Web Output 137 | *.[Pp]ublish.xml 138 | *.azurePubxml 139 | # TODO: Comment the next line if you want to checkin your web deploy settings 140 | # but database connection strings (with potential passwords) will be unencrypted 141 | *.pubxml 142 | *.publishproj 143 | 144 | # NuGet Packages 145 | *.nupkg 146 | # The packages folder can be ignored because of Package Restore 147 | **/packages/* 148 | # except build/, which is used as an MSBuild target. 149 | !**/packages/build/ 150 | # Uncomment if necessary however generally it will be regenerated when needed 151 | #!**/packages/repositories.config 152 | 153 | # Microsoft Azure Build Output 154 | csx/ 155 | *.build.csdef 156 | 157 | # Microsoft Azure Emulator 158 | ecf/ 159 | rcf/ 160 | 161 | # Microsoft Azure ApplicationInsights config file 162 | ApplicationInsights.config 163 | 164 | # Windows Store app package directory 165 | AppPackages/ 166 | BundleArtifacts/ 167 | 168 | # Visual Studio cache files 169 | # files ending in .cache can be ignored 170 | *.[Cc]ache 171 | # but keep track of directories ending in .cache 172 | !*.[Cc]ache/ 173 | 174 | # Others 175 | ClientBin/ 176 | ~$* 177 | *~ 178 | *.dbmdl 179 | *.dbproj.schemaview 180 | *.pfx 181 | *.publishsettings 182 | orleans.codegen.cs 183 | 184 | /node_modules 185 | 186 | # RIA/Silverlight projects 187 | Generated_Code/ 188 | 189 | # Backup & report files from converting an old project file 190 | # to a newer Visual Studio version. Backup files are not needed, 191 | # because we have git ;-) 192 | _UpgradeReport_Files/ 193 | Backup*/ 194 | UpgradeLog*.XML 195 | UpgradeLog*.htm 196 | 197 | # SQL Server files 198 | *.mdf 199 | *.ldf 200 | 201 | # Business Intelligence projects 202 | *.rdl.data 203 | *.bim.layout 204 | *.bim_*.settings 205 | 206 | # Microsoft Fakes 207 | FakesAssemblies/ 208 | 209 | # GhostDoc plugin setting file 210 | *.GhostDoc.xml 211 | 212 | # Node.js Tools for Visual Studio 213 | .ntvs_analysis.dat 214 | 215 | # Visual Studio 6 build log 216 | *.plg 217 | 218 | # Visual Studio 6 workspace options file 219 | *.opt 220 | 221 | # Visual Studio LightSwitch build output 222 | **/*.HTMLClient/GeneratedArtifacts 223 | **/*.DesktopClient/GeneratedArtifacts 224 | **/*.DesktopClient/ModelManifest.xml 225 | **/*.Server/GeneratedArtifacts 226 | **/*.Server/ModelManifest.xml 227 | _Pvt_Extensions 228 | 229 | # Paket dependency manager 230 | .paket/paket.exe 231 | 232 | # FAKE - F# Make 233 | .fake/ 234 | -------------------------------------------------------------------------------- /ClientApp/ClientApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp2.2 5 | InProcess 6 | true 7 | Latest 8 | false 9 | ClientApp\ 10 | $(DefaultItemExcludes);$(SpaRoot)node_modules\** 11 | 12 | 13 | false 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | %(DistFiles.Identity) 49 | PreserveNewest 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "ClientApp" 5 | }, 6 | "apps": [ 7 | { 8 | "root": "src", 9 | "outDir": "dist", 10 | "assets": [ 11 | "assets" 12 | ], 13 | "index": "index.html", 14 | "main": "main.ts", 15 | "polyfills": "polyfills.ts", 16 | "test": "test.ts", 17 | "tsconfig": "tsconfig.app.json", 18 | "testTsconfig": "tsconfig.spec.json", 19 | "prefix": "app", 20 | "styles": [ 21 | "styles.css", 22 | "../node_modules/bootstrap/dist/css/bootstrap.min.css" 23 | ], 24 | "scripts": [], 25 | "environmentSource": "environments/environment.ts", 26 | "environments": { 27 | "dev": "environments/environment.ts", 28 | "prod": "environments/environment.prod.ts" 29 | } 30 | } 31 | ], 32 | "e2e": { 33 | "protractor": { 34 | "config": "./protractor.conf.js" 35 | } 36 | }, 37 | "lint": [ 38 | { 39 | "project": "src/tsconfig.app.json", 40 | "exclude": "**/node_modules/**" 41 | }, 42 | { 43 | "project": "src/tsconfig.spec.json", 44 | "exclude": "**/node_modules/**" 45 | }, 46 | { 47 | "project": "e2e/tsconfig.e2e.json", 48 | "exclude": "**/node_modules/**" 49 | } 50 | ], 51 | "test": { 52 | "karma": { 53 | "config": "./karma.conf.js" 54 | } 55 | }, 56 | "defaults": { 57 | "styleExt": "css", 58 | "component": {}, 59 | "build": { 60 | "progress": true 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /dist-server 6 | /tmp 7 | /out-tsc 8 | 9 | # dependencies 10 | /node_modules 11 | 12 | # IDEs and editors 13 | /.idea 14 | .project 15 | .classpath 16 | .c9/ 17 | *.launch 18 | .settings/ 19 | *.sublime-workspace 20 | 21 | # IDE - VSCode 22 | .vscode/* 23 | !.vscode/settings.json 24 | !.vscode/tasks.json 25 | !.vscode/launch.json 26 | !.vscode/extensions.json 27 | 28 | # misc 29 | /.sass-cache 30 | /connect.lock 31 | /coverage 32 | /libpeerconnection.log 33 | npm-debug.log 34 | testem.log 35 | /typings 36 | 37 | # e2e 38 | /e2e/*.js 39 | /e2e/*.map 40 | 41 | # System Files 42 | .DS_Store 43 | Thumbs.db 44 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/README.md: -------------------------------------------------------------------------------- 1 | # ClientApp 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 1.7.0. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | 3 | describe('App', () => { 4 | let page: AppPage; 5 | 6 | beforeEach(() => { 7 | page = new AppPage(); 8 | }); 9 | 10 | it('should display welcome message', () => { 11 | page.navigateTo(); 12 | expect(page.getMainHeading()).toEqual('Hello, world!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getMainHeading() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": [ 9 | "jasmine", 10 | "jasminewd2", 11 | "node" 12 | ] 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular/cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | angularCli: { 23 | environment: 'dev' 24 | }, 25 | reporters: ['progress', 'kjhtml'], 26 | port: 9876, 27 | colors: true, 28 | logLevel: config.LOG_INFO, 29 | autoWatch: true, 30 | browsers: ['Chrome'], 31 | singleRun: false 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ClientApp", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve --extract-css", 8 | "build": "ng build --extract-css", 9 | "build:ssr": "npm run build -- --app=ssr --output-hashing=media", 10 | "test": "ng test", 11 | "lint": "ng lint", 12 | "e2e": "ng e2e" 13 | }, 14 | "private": true, 15 | "dependencies": { 16 | "@angular/animations": "^5.2.0", 17 | "@angular/common": "^5.2.0", 18 | "@angular/compiler": "^5.2.0", 19 | "@angular/core": "^5.2.0", 20 | "@angular/forms": "^5.2.0", 21 | "@angular/http": "^5.2.0", 22 | "@angular/platform-browser": "^5.2.0", 23 | "@angular/platform-browser-dynamic": "^5.2.0", 24 | "@angular/platform-server": "^5.2.0", 25 | "@angular/router": "^5.2.0", 26 | "@nguniversal/module-map-ngfactory-loader": "^5.0.0-beta.5", 27 | "aspnet-prerendering": "^3.0.1", 28 | "bootstrap": "^3.3.7", 29 | "core-js": "^2.4.1", 30 | "rxjs": "^5.5.6", 31 | "zone.js": "^0.8.19", 32 | "angular-auth-oidc-client": "3.0.9" 33 | }, 34 | "devDependencies": { 35 | "@angular/cli": "~1.7.0", 36 | "@angular/compiler-cli": "^5.2.0", 37 | "@angular/language-service": "^5.2.0", 38 | "@types/jasmine": "~2.8.3", 39 | "@types/jasminewd2": "~2.0.2", 40 | "@types/node": "~6.0.60", 41 | "codelyzer": "^4.0.1", 42 | "jasmine-core": "~2.8.0", 43 | "jasmine-spec-reporter": "~4.2.1", 44 | "karma": "~2.0.0", 45 | "karma-chrome-launcher": "~2.2.0", 46 | "karma-coverage-istanbul-reporter": "^1.2.1", 47 | "karma-jasmine": "~1.1.0", 48 | "karma-jasmine-html-reporter": "^0.2.2", 49 | "protractor": "~5.1.2", 50 | "ts-node": "~4.1.0", 51 | "tslint": "~5.9.1", 52 | "typescript": "~2.5.3" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | @media (max-width: 767px) { 2 | /* On small screens, the nav menu spans the full width of the screen. Leave a space for it. */ 3 | .body-content { 4 | padding-top: 50px; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
7 | 8 |
9 |
10 |
11 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-root', 5 | templateUrl: './app.component.html', 6 | styleUrls: ['./app.component.css'] 7 | }) 8 | export class AppComponent { 9 | title = 'app'; 10 | } 11 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule, APP_INITIALIZER } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { HttpClientModule } from '@angular/common/http'; 5 | import { RouterModule } from '@angular/router'; 6 | 7 | import { AppComponent } from './app.component'; 8 | import { NavMenuComponent } from './nav-menu/nav-menu.component'; 9 | import { HomeComponent } from './home/home.component'; 10 | import { CounterComponent } from './counter/counter.component'; 11 | import { FetchDataComponent } from './fetch-data/fetch-data.component'; 12 | import { UnauthorizedComponent } from './unauthorized/unauthorized.component'; 13 | import { ConfigurationService } from "./configuration/configuration.service"; 14 | 15 | import { AuthModule, OidcSecurityService } from 'angular-auth-oidc-client'; 16 | import { AuthService } from './services/auth.service'; 17 | 18 | const appInitializerFn = (appConfig: ConfigurationService) => { 19 | return () => { 20 | return appConfig.loadConfig(); 21 | }; 22 | }; 23 | 24 | @NgModule({ 25 | declarations: [ 26 | AppComponent, 27 | NavMenuComponent, 28 | HomeComponent, 29 | CounterComponent, 30 | FetchDataComponent, 31 | UnauthorizedComponent 32 | ], 33 | imports: [ 34 | BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }), 35 | AuthModule.forRoot(), 36 | HttpClientModule, 37 | FormsModule, 38 | RouterModule.forRoot([ 39 | { path: '', component: HomeComponent, pathMatch: 'full' }, 40 | { path: 'counter', component: CounterComponent }, 41 | { path: 'fetch-data', component: FetchDataComponent }, 42 | { path: 'unauthorized', component: UnauthorizedComponent } 43 | ]) 44 | ], 45 | providers: [ 46 | { provide: 'ORIGIN_URL', useFactory: getBaseUrl }, 47 | AuthService, 48 | OidcSecurityService, 49 | ConfigurationService, 50 | { 51 | provide: APP_INITIALIZER, 52 | useFactory: appInitializerFn, 53 | multi: true, 54 | deps: [ConfigurationService] 55 | }], 56 | bootstrap: [AppComponent] 57 | }) 58 | export class AppModule { } 59 | 60 | export function getBaseUrl() { 61 | return document.getElementsByTagName('base')[0].href; 62 | } 63 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/configuration/configuration.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import 'rxjs/add/operator/map'; 4 | 5 | @Injectable() 6 | export class ConfigurationService { 7 | 8 | private configuration: IServerConfiguration; 9 | 10 | constructor(private http: HttpClient) { } 11 | 12 | loadConfig() { 13 | return this.http.get('/api/Configuration/ConfigurationData') 14 | .toPromise() 15 | .then(result => { 16 | this.configuration = (result); 17 | }, error => console.error(error)); 18 | } 19 | 20 | get apiAddress() { 21 | return this.configuration.ApiAddress; 22 | } 23 | 24 | get identityServerAddress() { 25 | return this.configuration.IdentityServerAddress; 26 | } 27 | 28 | } 29 | 30 | export interface IServerConfiguration { 31 | ApiAddress: string; 32 | IdentityServerAddress: string; 33 | } 34 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/counter/counter.component.html: -------------------------------------------------------------------------------- 1 |

Counter

2 | 3 |

This is a simple example of an Angular component.

4 | 5 |

Current count: {{ currentCount }}

6 | 7 | 8 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/counter/counter.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CounterComponent } from './counter.component'; 4 | 5 | describe('CounterComponent', () => { 6 | let component: CounterComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CounterComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CounterComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should display a title', async(() => { 23 | const titleText = fixture.nativeElement.querySelector('h1').textContent; 24 | expect(titleText).toEqual('Counter'); 25 | })); 26 | 27 | it('should start with count 0, then increments by 1 when clicked', async(() => { 28 | const countElement = fixture.nativeElement.querySelector('strong'); 29 | expect(countElement.textContent).toEqual('0'); 30 | 31 | const incrementButton = fixture.nativeElement.querySelector('button'); 32 | incrementButton.click(); 33 | fixture.detectChanges(); 34 | expect(countElement.textContent).toEqual('1'); 35 | })); 36 | }); 37 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/counter/counter.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-counter-component', 5 | templateUrl: './counter.component.html' 6 | }) 7 | export class CounterComponent { 8 | public currentCount = 0; 9 | 10 | public incrementCounter() { 11 | this.currentCount++; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/fetch-data/fetch-data.component.html: -------------------------------------------------------------------------------- 1 |

Weather forecast

2 | 3 |

This component demonstrates fetching data from the server.

4 | 5 |

Loading...

6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
DateTemp. (C)Temp. (F)Summary
{{ forecast.dateFormatted }}{{ forecast.temperatureC }}{{ forecast.temperatureF }}{{ forecast.summary }}
25 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/fetch-data/fetch-data.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { AuthService } from '../services/auth.service'; 3 | import { ConfigurationService } from "../configuration/configuration.service"; 4 | 5 | @Component({ 6 | selector: 'app-fetch-data', 7 | templateUrl: './fetch-data.component.html' 8 | }) 9 | export class FetchDataComponent { 10 | public forecasts: WeatherForecast[]; 11 | 12 | constructor(authService: AuthService, configuration: ConfigurationService) { 13 | authService.get(configuration.apiAddress + 'SampleData/WeatherForecasts').subscribe(result => { 14 | this.forecasts = result as WeatherForecast[]; 15 | }, error => console.error(error)); 16 | } 17 | } 18 | 19 | interface WeatherForecast { 20 | dateFormatted: string; 21 | temperatureC: number; 22 | temperatureF: number; 23 | summary: string; 24 | } 25 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/home/home.component.html: -------------------------------------------------------------------------------- 1 |

Hello, world!

2 |

Welcome to your new single-page application, built with:

3 | 8 |

To help you get started, we've also set up:

9 |
    10 |
  • Client-side navigation. For example, click Counter then Back to return here.
  • 11 |
  • Angular CLI integration. In development mode, there's no need to run ng serve. It runs in the background automatically, so your client-side resources are dynamically built on demand and the page refreshes when you modify any file.
  • 12 |
  • Efficient production builds. In production mode, development-time features are disabled, and your dotnet publish configuration automatically invokes ng build to produce minified, ahead-of-time compiled JavaScript files.
  • 13 |
14 |

The ClientApp subdirectory is a standard Angular CLI application. If you open a command prompt in that directory, you can run any ng command (e.g., ng test), or use npm to install extra packages into it.

15 |

If you want to enable server-side prerendering, see the steps in Startup.cs.

16 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/home/home.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-home', 5 | templateUrl: './home.component.html', 6 | }) 7 | export class HomeComponent { 8 | } 9 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/nav-menu/nav-menu.component.css: -------------------------------------------------------------------------------- 1 | li .glyphicon { 2 | margin-right: 10px; 3 | } 4 | 5 | /* Highlighting rules for nav menu items */ 6 | li.link-active a, 7 | li.link-active a:hover, 8 | li.link-active a:focus { 9 | background-color: #4189C7; 10 | color: white; 11 | } 12 | 13 | /* Keep the nav menu independent of scrolling and on top of other items */ 14 | .main-nav { 15 | position: fixed; 16 | top: 0; 17 | left: 0; 18 | right: 0; 19 | z-index: 1; 20 | } 21 | 22 | @media (min-width: 768px) { 23 | /* On small screens, convert the nav menu to a vertical sidebar */ 24 | .main-nav { 25 | height: 100%; 26 | width: calc(25% - 20px); 27 | } 28 | .navbar { 29 | border-radius: 0px; 30 | border-width: 0px; 31 | height: 100%; 32 | } 33 | .navbar-header { 34 | float: none; 35 | } 36 | .navbar-collapse { 37 | border-top: 1px solid #444; 38 | padding: 0px; 39 | } 40 | .navbar ul { 41 | float: none; 42 | } 43 | .navbar li { 44 | float: none; 45 | font-size: 15px; 46 | margin: 6px; 47 | } 48 | .navbar li a { 49 | padding: 10px 16px; 50 | border-radius: 4px; 51 | } 52 | .navbar a { 53 | /* If a menu item's text is too long, truncate it */ 54 | width: 100%; 55 | white-space: nowrap; 56 | overflow: hidden; 57 | text-overflow: ellipsis; 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/nav-menu/nav-menu.component.html: -------------------------------------------------------------------------------- 1 | 38 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/nav-menu/nav-menu.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, OnDestroy } from '@angular/core'; 2 | import { Subscription } from 'rxjs/Subscription'; 3 | 4 | import { AuthService } from '../services/auth.service'; 5 | 6 | 7 | @Component({ 8 | selector: 'app-nav-menu', 9 | templateUrl: './nav-menu.component.html', 10 | styleUrls: ['./nav-menu.component.css'] 11 | }) 12 | export class NavMenuComponent implements OnInit, OnDestroy { 13 | isAuthorizedSubscription: Subscription; 14 | isAuthorized: boolean; 15 | isExpanded = false; 16 | 17 | constructor(public authService: AuthService) { 18 | } 19 | 20 | ngOnInit() { 21 | this.isAuthorizedSubscription = this.authService.getIsAuthorized().subscribe( 22 | (isAuthorized: boolean) => { 23 | this.isAuthorized = isAuthorized; 24 | }); 25 | } 26 | 27 | ngOnDestroy(): void { 28 | this.isAuthorizedSubscription.unsubscribe(); 29 | } 30 | 31 | public login() { 32 | this.authService.login(); 33 | } 34 | 35 | public refreshSession() { 36 | this.authService.refreshSession(); 37 | } 38 | 39 | public logout() { 40 | this.authService.logout(); 41 | } 42 | 43 | collapse() { 44 | this.isExpanded = false; 45 | } 46 | 47 | toggle() { 48 | this.isExpanded = !this.isExpanded; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/services/auth.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Component, OnInit, OnDestroy, Inject } from '@angular/core'; 2 | import { HttpClient, HttpHeaders } from '@angular/common/http'; 3 | import { Observable } from 'rxjs/Rx'; 4 | import { Subscription } from 'rxjs/Subscription'; 5 | import { ConfigurationService } from "../configuration/configuration.service"; 6 | 7 | import { OidcSecurityService, OpenIDImplicitFlowConfiguration } from 'angular-auth-oidc-client'; 8 | 9 | @Injectable() 10 | export class AuthService implements OnInit, OnDestroy { 11 | isAuthorizedSubscription: Subscription; 12 | isAuthorized: boolean; 13 | 14 | constructor(public oidcSecurityService: OidcSecurityService, 15 | private http: HttpClient, 16 | @Inject('ORIGIN_URL') originUrl: string, 17 | configuration: ConfigurationService 18 | ) { 19 | const openIdImplicitFlowConfiguration = new OpenIDImplicitFlowConfiguration(); 20 | openIdImplicitFlowConfiguration.stsServer = configuration.identityServerAddress; 21 | openIdImplicitFlowConfiguration.redirect_url = originUrl; 22 | openIdImplicitFlowConfiguration.client_id = 'ng'; 23 | openIdImplicitFlowConfiguration.response_type = 'id_token token'; 24 | openIdImplicitFlowConfiguration.scope = 'openid profile apiApp'; 25 | openIdImplicitFlowConfiguration.post_logout_redirect_uri = originUrl + 'home'; 26 | openIdImplicitFlowConfiguration.forbidden_route = '/forbidden'; 27 | openIdImplicitFlowConfiguration.unauthorized_route = '/unauthorized'; 28 | openIdImplicitFlowConfiguration.auto_userinfo = true; 29 | openIdImplicitFlowConfiguration.log_console_warning_active = true; 30 | openIdImplicitFlowConfiguration.log_console_debug_active = false; 31 | openIdImplicitFlowConfiguration.max_id_token_iat_offset_allowed_in_seconds = 10; 32 | 33 | this.oidcSecurityService.setupModule(openIdImplicitFlowConfiguration); 34 | 35 | if (this.oidcSecurityService.moduleSetup) { 36 | this.doCallbackLogicIfRequired(); 37 | } else { 38 | this.oidcSecurityService.onModuleSetup.subscribe(() => { 39 | this.doCallbackLogicIfRequired(); 40 | }); 41 | } 42 | } 43 | 44 | ngOnInit() { 45 | this.isAuthorizedSubscription = this.oidcSecurityService.getIsAuthorized().subscribe( 46 | (isAuthorized: boolean) => { 47 | this.isAuthorized = isAuthorized; 48 | }); 49 | } 50 | 51 | ngOnDestroy(): void { 52 | this.isAuthorizedSubscription.unsubscribe(); 53 | this.oidcSecurityService.onModuleSetup.unsubscribe(); 54 | } 55 | 56 | getIsAuthorized(): Observable { 57 | return this.oidcSecurityService.getIsAuthorized(); 58 | } 59 | 60 | login() { 61 | console.log('start login'); 62 | this.oidcSecurityService.authorize(); 63 | } 64 | 65 | refreshSession() { 66 | console.log('start refreshSession'); 67 | this.oidcSecurityService.authorize(); 68 | } 69 | 70 | logout() { 71 | console.log('start logoff'); 72 | this.oidcSecurityService.logoff(); 73 | } 74 | 75 | private doCallbackLogicIfRequired() { 76 | if (typeof location !== "undefined" && window.location.hash) { 77 | this.oidcSecurityService.authorizedCallback(); 78 | } 79 | } 80 | 81 | get(url: string): Observable { 82 | return this.http.get(url, { headers: this.getHeaders() }); 83 | } 84 | 85 | put(url: string, data: any): Observable { 86 | const body = JSON.stringify(data); 87 | return this.http.put(url, body, { headers: this.getHeaders() }); 88 | } 89 | 90 | delete(url: string): Observable { 91 | return this.http.delete(url, { headers: this.getHeaders() }); 92 | } 93 | 94 | post(url: string, data: any): Observable { 95 | const body = JSON.stringify(data); 96 | return this.http.post(url, body, { headers: this.getHeaders() }); 97 | } 98 | 99 | private getHeaders() { 100 | let headers = new HttpHeaders(); 101 | headers = headers.set('Content-Type', 'application/json'); 102 | return this.appendAuthHeader(headers); 103 | } 104 | 105 | private appendAuthHeader(headers: HttpHeaders) { 106 | const token = this.oidcSecurityService.getToken(); 107 | 108 | if (token === '') return headers; 109 | 110 | const tokenValue = 'Bearer ' + token; 111 | return headers.set('Authorization', tokenValue); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/unauthorized/unauthorized.component.html: -------------------------------------------------------------------------------- 1 | 

2 | Login is required to access this area 3 |

4 |
5 | 6 | 7 |
-------------------------------------------------------------------------------- /ClientApp/ClientApp/src/app/unauthorized/unauthorized.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { Location } from '@angular/common'; 3 | 4 | @Component({ 5 | selector: 'app-unauthorized', 6 | templateUrl: 'unauthorized.component.html' 7 | }) 8 | export class UnauthorizedComponent implements OnInit { 9 | 10 | constructor(private location: Location) { 11 | 12 | } 13 | 14 | ngOnInit() { 15 | } 16 | 17 | login() { 18 | //this.service.startSigninMainWindow(); 19 | } 20 | 21 | goback() { 22 | this.location.back(); 23 | } 24 | } -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/ClientApp/ClientApp/src/assets/.gitkeep -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ClientApp 6 | 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | export function getBaseUrl() { 8 | return document.getElementsByTagName('base')[0].href; 9 | } 10 | 11 | const providers = [ 12 | { provide: 'BASE_URL', useFactory: getBaseUrl, deps: [] } 13 | ]; 14 | 15 | if (environment.production) { 16 | enableProdMode(); 17 | } 18 | 19 | platformBrowserDynamic(providers).bootstrapModule(AppModule) 20 | .catch(err => console.log(err)); 21 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following for the Reflect API. */ 41 | // import 'core-js/es6/reflect'; 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | // Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove. 46 | import 'core-js/es7/reflect'; 47 | 48 | 49 | /** 50 | * Required to support Web Animations `@angular/platform-browser/animations`. 51 | * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation 52 | **/ 53 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 54 | 55 | /** 56 | * By default, zone.js will patch all possible macroTask and DomEvents 57 | * user can disable parts of macroTask/DomEvents patch by setting following flags 58 | */ 59 | 60 | // (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 61 | // (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 62 | // (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 63 | 64 | /* 65 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 66 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 67 | */ 68 | // (window as any).__Zone_enable_cross_context_check = true; 69 | 70 | /*************************************************************************************************** 71 | * Zone JS is required by default for Angular itself. 72 | */ 73 | import 'zone.js/dist/zone'; // Included with Angular CLI. 74 | 75 | 76 | 77 | /*************************************************************************************************** 78 | * APPLICATION IMPORTS 79 | */ 80 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "baseUrl": "./", 6 | "module": "es2015", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "baseUrl": "./", 6 | "module": "commonjs", 7 | "types": [ 8 | "jasmine", 9 | "node" 10 | ] 11 | }, 12 | "files": [ 13 | "test.ts" 14 | ], 15 | "include": [ 16 | "**/*.spec.ts", 17 | "**/*.d.ts" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "target": "es5", 11 | "typeRoots": [ 12 | "node_modules/@types" 13 | ], 14 | "lib": [ 15 | "es2017", 16 | "dom" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ClientApp/ClientApp/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "deprecation": { 15 | "severity": "warn" 16 | }, 17 | "eofline": true, 18 | "forin": true, 19 | "import-blacklist": [ 20 | true, 21 | "rxjs", 22 | "rxjs/Rx" 23 | ], 24 | "import-spacing": true, 25 | "indent": [ 26 | true, 27 | "spaces" 28 | ], 29 | "interface-over-type-literal": true, 30 | "label-position": true, 31 | "max-line-length": [ 32 | true, 33 | 140 34 | ], 35 | "member-access": false, 36 | "member-ordering": [ 37 | true, 38 | { 39 | "order": [ 40 | "static-field", 41 | "instance-field", 42 | "static-method", 43 | "instance-method" 44 | ] 45 | } 46 | ], 47 | "no-arg": true, 48 | "no-bitwise": true, 49 | "no-console": [ 50 | true, 51 | "debug", 52 | "info", 53 | "time", 54 | "timeEnd", 55 | "trace" 56 | ], 57 | "no-construct": true, 58 | "no-debugger": true, 59 | "no-duplicate-super": true, 60 | "no-empty": false, 61 | "no-empty-interface": true, 62 | "no-eval": true, 63 | "no-inferrable-types": [ 64 | true, 65 | "ignore-params" 66 | ], 67 | "no-misused-new": true, 68 | "no-non-null-assertion": true, 69 | "no-shadowed-variable": true, 70 | "no-string-literal": false, 71 | "no-string-throw": true, 72 | "no-switch-case-fall-through": true, 73 | "no-trailing-whitespace": true, 74 | "no-unnecessary-initializer": true, 75 | "no-unused-expression": true, 76 | "no-use-before-declare": true, 77 | "no-var-keyword": true, 78 | "object-literal-sort-keys": false, 79 | "one-line": [ 80 | true, 81 | "check-open-brace", 82 | "check-catch", 83 | "check-else", 84 | "check-whitespace" 85 | ], 86 | "prefer-const": true, 87 | "quotemark": [ 88 | true, 89 | "single" 90 | ], 91 | "radix": true, 92 | "semicolon": [ 93 | true, 94 | "always" 95 | ], 96 | "triple-equals": [ 97 | true, 98 | "allow-null-check" 99 | ], 100 | "typedef-whitespace": [ 101 | true, 102 | { 103 | "call-signature": "nospace", 104 | "index-signature": "nospace", 105 | "parameter": "nospace", 106 | "property-declaration": "nospace", 107 | "variable-declaration": "nospace" 108 | } 109 | ], 110 | "unified-signatures": true, 111 | "variable-name": false, 112 | "whitespace": [ 113 | true, 114 | "check-branch", 115 | "check-decl", 116 | "check-operator", 117 | "check-separator", 118 | "check-type" 119 | ], 120 | "directive-selector": [ 121 | true, 122 | "attribute", 123 | "app", 124 | "camelCase" 125 | ], 126 | "component-selector": [ 127 | true, 128 | "element", 129 | "app", 130 | "kebab-case" 131 | ], 132 | "no-output-on-prefix": true, 133 | "use-input-property-decorator": true, 134 | "use-output-property-decorator": true, 135 | "use-host-property-decorator": true, 136 | "no-input-rename": true, 137 | "no-output-rename": true, 138 | "use-life-cycle-interface": true, 139 | "use-pipe-transform-interface": true, 140 | "component-class-suffix": true, 141 | "directive-class-suffix": true 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /ClientApp/Controllers/ConfigurationController.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace ClientApp.Controllers 6 | { 7 | [Produces("application/json")] 8 | [Route("api/Configuration")] 9 | public class ConfigurationController : Controller 10 | { 11 | private readonly IConfiguration _configuration; 12 | 13 | public ConfigurationController(IConfiguration configuration) 14 | { 15 | _configuration = configuration; 16 | } 17 | 18 | [HttpGet("[action]")] 19 | public IActionResult ConfigurationData() 20 | { 21 | return Ok(new Dictionary 22 | { 23 | { "IdentityServerAddress", _configuration["IdentityServerAddress"] }, 24 | { "ApiAddress", _configuration["ApiAddress"] } 25 | }); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /ClientApp/Controllers/IdentityController.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Threading.Tasks; 3 | using IdentityModel.Client; 4 | using Microsoft.AspNetCore.Authentication; 5 | using Microsoft.AspNetCore.Authorization; 6 | using Microsoft.AspNetCore.Mvc; 7 | 8 | namespace ClientApp.Controllers 9 | { 10 | public class IdentityController : Controller 11 | { 12 | [Authorize] 13 | public async Task Index() 14 | { 15 | var apiCallUsingUserAccessToken = await ApiCallUsingUserAccessToken(); 16 | ViewData["apiCallUsingUserAccessToken"] = apiCallUsingUserAccessToken.IsSuccessStatusCode ? await apiCallUsingUserAccessToken.Content.ReadAsStringAsync() : apiCallUsingUserAccessToken.StatusCode.ToString(); 17 | 18 | var clientCredentialsResponse = await ApiCallUsingClientCredentials(); 19 | ViewData["clientCredentialsResponse"] = clientCredentialsResponse.IsSuccessStatusCode ? await clientCredentialsResponse.Content.ReadAsStringAsync() : clientCredentialsResponse.StatusCode.ToString(); 20 | 21 | return View(); 22 | } 23 | 24 | private async Task ApiCallUsingUserAccessToken() 25 | { 26 | var accessToken = await HttpContext.GetTokenAsync("access_token"); 27 | 28 | var client = new HttpClient(); 29 | client.SetBearerToken(accessToken); 30 | 31 | return await client.GetAsync("http://localhost:5001/api/identity"); 32 | } 33 | 34 | private async Task ApiCallUsingClientCredentials() 35 | { 36 | var tokenClient = new TokenClient("http://localhost:5000/connect/token", "mvc", "secret"); 37 | var tokenResponse = await tokenClient.RequestClientCredentialsAsync("apiApp"); 38 | 39 | var client = new HttpClient(); 40 | client.SetBearerToken(tokenResponse.AccessToken); 41 | 42 | return await client.GetAsync("http://localhost:5001/api/identity"); 43 | } 44 | 45 | public async Task Logout() 46 | { 47 | await HttpContext.SignOutAsync("Cookies"); 48 | await HttpContext.SignOutAsync("oidc"); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ClientApp/Controllers/SampleDataController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | 7 | namespace ClientApp.Controllers 8 | { 9 | [Route("api/[controller]")] 10 | public class SampleDataController : Controller 11 | { 12 | private static string[] Summaries = new[] 13 | { 14 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 15 | }; 16 | 17 | [HttpGet("[action]")] 18 | public IEnumerable WeatherForecasts() 19 | { 20 | var rng = new Random(); 21 | return Enumerable.Range(1, 5).Select(index => new WeatherForecast 22 | { 23 | DateFormatted = DateTime.Now.AddDays(index).ToString("d"), 24 | TemperatureC = rng.Next(-20, 55), 25 | Summary = Summaries[rng.Next(Summaries.Length)] 26 | }); 27 | } 28 | 29 | public class WeatherForecast 30 | { 31 | public string DateFormatted { get; set; } 32 | public int TemperatureC { get; set; } 33 | public string Summary { get; set; } 34 | 35 | public int TemperatureF 36 | { 37 | get 38 | { 39 | return 32 + (int)(TemperatureC / 0.5556); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ClientApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace ClientApp 12 | { 13 | public class Program 14 | { 15 | public static void Main(string[] args) 16 | { 17 | CreateWebHostBuilder(args).Build().Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 21 | WebHost.CreateDefaultBuilder(args) 22 | .UseStartup(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /ClientApp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:5002/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "ClientApp": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "http://localhost:5002/" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /ClientApp/Startup.cs: -------------------------------------------------------------------------------- 1 | using System.IdentityModel.Tokens.Jwt; 2 | using Microsoft.AspNetCore.Authentication.Cookies; 3 | using Microsoft.AspNetCore.Authentication.OpenIdConnect; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.SpaServices.AngularCli; 8 | using Microsoft.Extensions.Configuration; 9 | using Microsoft.Extensions.DependencyInjection; 10 | 11 | namespace ClientApp 12 | { 13 | public class Startup 14 | { 15 | public Startup(IConfiguration configuration) 16 | { 17 | Configuration = configuration; 18 | } 19 | 20 | public IConfiguration Configuration { get; } 21 | 22 | // This method gets called by the runtime. Use this method to add services to the container. 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 26 | 27 | // In production, the Angular files will be served from this directory 28 | services.AddSpaStaticFiles(configuration => 29 | { 30 | configuration.RootPath = "ClientApp/dist"; 31 | }); 32 | 33 | services.AddAuthentication(options => 34 | { 35 | options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; 36 | options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; 37 | }) 38 | .AddCookie() 39 | .AddOpenIdConnect(options => 40 | { 41 | options.Authority = Configuration["IdentityServerAddress"]; 42 | options.RequireHttpsMetadata = false; 43 | 44 | options.ClientId = "mvc"; 45 | options.ClientSecret = "secret"; 46 | 47 | options.ResponseType = "code id_token"; 48 | options.Scope.Add("apiApp"); 49 | options.Scope.Add("offline_access"); 50 | 51 | options.GetClaimsFromUserInfoEndpoint = true; 52 | options.SaveTokens = true; 53 | }); 54 | } 55 | 56 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 57 | public void Configure(IApplicationBuilder app, IHostingEnvironment env) 58 | { 59 | JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); 60 | 61 | if (env.IsDevelopment()) 62 | { 63 | app.UseDeveloperExceptionPage(); 64 | } 65 | else 66 | { 67 | app.UseExceptionHandler("/Home/Error"); 68 | } 69 | 70 | app.UseStaticFiles(); 71 | app.UseSpaStaticFiles(); 72 | 73 | app.UseMvc(routes => 74 | { 75 | routes.MapRoute( 76 | name: "default", 77 | template: "{controller}/{action=Index}/{id?}"); 78 | }); 79 | 80 | app.UseSpa(spa => 81 | { 82 | // To learn more about options for serving an Angular SPA from ASP.NET Core, 83 | // see https://go.microsoft.com/fwlink/?linkid=864501 84 | 85 | spa.Options.SourcePath = "ClientApp"; 86 | 87 | if (env.IsDevelopment()) 88 | { 89 | spa.UseAngularCliServer(npmScript: "start"); 90 | } 91 | }); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /ClientApp/Views/Identity/Index.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Authentication 2 | @{ 3 | ViewData["Title"] = "Identity"; 4 | } 5 | 6 |
access token
7 |
@await ViewContext.HttpContext.GetTokenAsync("access_token")
8 | 9 |
refresh token
10 |
@await ViewContext.HttpContext.GetTokenAsync("refresh_token")
11 | 12 |
api response called with user access token
13 |
@ViewData["apiCallUsingUserAccessToken"]
14 | 15 |
api response called with client credentials
16 |
@ViewData["clientCredentialsResponse"]
17 | 18 |

User claims

19 | 20 |
21 | @foreach (var claim in User.Claims) 22 | { 23 |
@claim.Type
24 |
@claim.Value
25 | } 26 |
27 | 28 |
29 | 30 |
-------------------------------------------------------------------------------- /ClientApp/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Error"; 3 | } 4 | 5 |

Error.

6 |

An error occurred while processing your request.

7 | 8 | @if (!string.IsNullOrEmpty((string)ViewData["RequestId"])) 9 | { 10 |

11 | Request ID: @ViewData["RequestId"] 12 |

13 | } 14 | 15 |

Development Mode

16 |

17 | Swapping to Development environment will display more detailed information about the error that occurred. 18 |

19 |

20 | Development environment should not be enabled in deployed applications, as it can result in sensitive information from exceptions being displayed to end users. For local debugging, development environment can be enabled by setting the ASPNETCORE_ENVIRONMENT environment variable to Development, and restarting the application. 21 |

-------------------------------------------------------------------------------- /ClientApp/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - Client App 7 | 8 | 9 | 10 | 11 | 12 | @RenderBody() 13 | 14 | @RenderSection("scripts", required: false) 15 | 16 | -------------------------------------------------------------------------------- /ClientApp/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using ClientApp 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | @addTagHelper *, Microsoft.AspNetCore.SpaServices -------------------------------------------------------------------------------- /ClientApp/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } -------------------------------------------------------------------------------- /ClientApp/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Debug", 5 | "System": "Information", 6 | "Microsoft": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /ClientApp/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Warning" 5 | } 6 | }, 7 | "IdentityServerAddress": "http://localhost:5000", 8 | "ApiAddress": "http://localhost:5001/api/" 9 | } 10 | -------------------------------------------------------------------------------- /ClientApp/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/ClientApp/wwwroot/favicon.ico -------------------------------------------------------------------------------- /IdentityApp/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "wwwroot/lib" 3 | } 4 | -------------------------------------------------------------------------------- /IdentityApp/Config.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using IdentityServer4; 3 | using IdentityServer4.Models; 4 | using Microsoft.Extensions.Configuration; 5 | 6 | namespace IdentityApp 7 | { 8 | public class Config 9 | { 10 | // scopes define the resources in your system 11 | public static IEnumerable GetIdentityResources() 12 | { 13 | return new List 14 | { 15 | new IdentityResources.OpenId(), 16 | new IdentityResources.Profile(), 17 | }; 18 | } 19 | 20 | public static IEnumerable GetApiResources() 21 | { 22 | return new List 23 | { 24 | new ApiResource("apiApp", "My API") 25 | }; 26 | } 27 | 28 | // clients want to access resources (aka scopes) 29 | public static IEnumerable GetClients(IConfiguration configuration) 30 | { 31 | // client credentials client 32 | return new List 33 | { 34 | new Client 35 | { 36 | ClientId = "clientApp", 37 | 38 | // no interactive user, use the clientid/secret for authentication 39 | AllowedGrantTypes = GrantTypes.ClientCredentials, 40 | 41 | // secret for authentication 42 | ClientSecrets = 43 | { 44 | new Secret("secret".Sha256()) 45 | }, 46 | 47 | // scopes that client has access to 48 | AllowedScopes = { "apiApp" } 49 | }, 50 | 51 | // OpenID Connect implicit flow client (MVC) 52 | new Client 53 | { 54 | ClientId = "mvc", 55 | ClientName = "MVC Client", 56 | AllowedGrantTypes = GrantTypes.HybridAndClientCredentials, 57 | 58 | RequireConsent = true, 59 | 60 | ClientSecrets = 61 | { 62 | new Secret("secret".Sha256()) 63 | }, 64 | 65 | RedirectUris = { $"{configuration["ClientAddress"]}/signin-oidc" }, 66 | PostLogoutRedirectUris = { $"{configuration["ClientAddress"]}/signout-callback-oidc" }, 67 | 68 | AllowedScopes = 69 | { 70 | IdentityServerConstants.StandardScopes.OpenId, 71 | IdentityServerConstants.StandardScopes.Profile, 72 | "apiApp" 73 | }, 74 | AllowOfflineAccess = true 75 | }, 76 | 77 | // OpenID Connect implicit flow client (Angular) 78 | new Client 79 | { 80 | ClientId = "ng", 81 | ClientName = "Angular Client", 82 | AllowedGrantTypes = GrantTypes.Implicit, 83 | AllowAccessTokensViaBrowser = true, 84 | RequireConsent = true, 85 | 86 | RedirectUris = { $"{configuration["ClientAddress"]}/" }, 87 | PostLogoutRedirectUris = { $"{configuration["ClientAddress"]}/home" }, 88 | AllowedCorsOrigins = { configuration["ClientAddress"] }, 89 | 90 | AllowedScopes = 91 | { 92 | IdentityServerConstants.StandardScopes.OpenId, 93 | IdentityServerConstants.StandardScopes.Profile, 94 | "apiApp" 95 | }, 96 | 97 | } 98 | 99 | }; 100 | } 101 | } 102 | } -------------------------------------------------------------------------------- /IdentityApp/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.AspNetCore.Mvc; 3 | using IdentityServer4.Services; 4 | using IdentityServer4.Quickstart.UI; 5 | 6 | namespace IdentityApp.Controllers 7 | { 8 | [SecurityHeaders] 9 | public class HomeController : Controller 10 | { 11 | private readonly IIdentityServerInteractionService _interaction; 12 | 13 | public HomeController(IIdentityServerInteractionService interaction) 14 | { 15 | _interaction = interaction; 16 | } 17 | 18 | public IActionResult Index() 19 | { 20 | return View(); 21 | } 22 | 23 | public IActionResult About() 24 | { 25 | ViewData["Message"] = "Your application description page."; 26 | 27 | return View(); 28 | } 29 | 30 | public IActionResult Contact() 31 | { 32 | ViewData["Message"] = "Your contact page."; 33 | 34 | return View(); 35 | } 36 | 37 | public async Task Error(string errorId) 38 | { 39 | var vm = new ErrorViewModel(); 40 | 41 | // retrieve error details from identityserver 42 | var message = await _interaction.GetErrorContextAsync(errorId); 43 | if (message != null) 44 | { 45 | vm.Error = message; 46 | } 47 | 48 | return View("Error", vm); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /IdentityApp/Data/ApplicationDbContext.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Identity.EntityFrameworkCore; 6 | using Microsoft.EntityFrameworkCore; 7 | using IdentityApp.Models; 8 | 9 | namespace IdentityApp.Data 10 | { 11 | public sealed class ApplicationDbContext : IdentityDbContext 12 | { 13 | public ApplicationDbContext(DbContextOptions options) 14 | : base(options) 15 | { 16 | } 17 | 18 | protected override void OnModelCreating(ModelBuilder builder) 19 | { 20 | base.OnModelCreating(builder); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /IdentityApp/Data/Migrations/IdentityServer/Configuration/20180109123644_Configration21.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace IdentityApp.Data.Migrations.IdentityServer.Configuration 6 | { 7 | public partial class Configration21 : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | 12 | } 13 | 14 | protected override void Down(MigrationBuilder migrationBuilder) 15 | { 16 | 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /IdentityApp/Data/Migrations/IdentityServer/IdentityServerDatabaseInitialization.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IdentityServer4.EntityFramework.DbContexts; 3 | using IdentityServer4.EntityFramework.Mappers; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using System.Linq; 7 | using Microsoft.Extensions.Configuration; 8 | 9 | namespace IdentityApp.Data.Migrations.IdentityServer 10 | { 11 | public static class IdentityServerDatabaseInitialization 12 | { 13 | public static void InitializeDatabase(IServiceProvider services) 14 | { 15 | PerformMigrations(services); 16 | SeedData(services); 17 | 18 | } 19 | 20 | private static void PerformMigrations(IServiceProvider services) 21 | { 22 | services.GetRequiredService().Database.Migrate(); 23 | services.GetRequiredService().Database.Migrate(); 24 | services.GetRequiredService().Database.Migrate(); 25 | } 26 | 27 | private static void SeedData(IServiceProvider services) 28 | { 29 | var context = services.GetRequiredService(); 30 | var config = services.GetRequiredService(); 31 | 32 | if (!context.Clients.Any()) 33 | { 34 | foreach (var client in Config.GetClients(config)) 35 | { 36 | context.Clients.Add(client.ToEntity()); 37 | } 38 | context.SaveChanges(); 39 | } 40 | 41 | if (!context.IdentityResources.Any()) 42 | { 43 | foreach (var resource in Config.GetIdentityResources()) 44 | { 45 | context.IdentityResources.Add(resource.ToEntity()); 46 | } 47 | context.SaveChanges(); 48 | } 49 | 50 | if (!context.ApiResources.Any()) 51 | { 52 | foreach (var resource in Config.GetApiResources()) 53 | { 54 | context.ApiResources.Add(resource.ToEntity()); 55 | } 56 | context.SaveChanges(); 57 | } 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /IdentityApp/Data/Migrations/IdentityServer/PersistedGrant/20171007184807_InitPersistedGrant.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using IdentityServer4.EntityFramework.DbContexts; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.Internal; 8 | using System; 9 | 10 | namespace IdentityApp.Data.Migrations.IdentityServer.PersistedGrant 11 | { 12 | [DbContext(typeof(PersistedGrantDbContext))] 13 | [Migration("20171007184807_InitPersistedGrant")] 14 | partial class InitPersistedGrant 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "2.0.0-rtm-26452") 21 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 22 | 23 | modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => 24 | { 25 | b.Property("Key") 26 | .HasMaxLength(200); 27 | 28 | b.Property("ClientId") 29 | .IsRequired() 30 | .HasMaxLength(200); 31 | 32 | b.Property("CreationTime"); 33 | 34 | b.Property("Data") 35 | .IsRequired() 36 | .HasMaxLength(50000); 37 | 38 | b.Property("Expiration"); 39 | 40 | b.Property("SubjectId") 41 | .HasMaxLength(200); 42 | 43 | b.Property("Type") 44 | .IsRequired() 45 | .HasMaxLength(50); 46 | 47 | b.HasKey("Key"); 48 | 49 | b.HasIndex("SubjectId", "ClientId", "Type"); 50 | 51 | b.ToTable("PersistedGrants"); 52 | }); 53 | #pragma warning restore 612, 618 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /IdentityApp/Data/Migrations/IdentityServer/PersistedGrant/20171007184807_InitPersistedGrant.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace IdentityApp.Data.Migrations.IdentityServer.PersistedGrant 6 | { 7 | public partial class InitPersistedGrant : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.CreateTable( 12 | name: "PersistedGrants", 13 | columns: table => new 14 | { 15 | Key = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), 16 | ClientId = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: false), 17 | CreationTime = table.Column(type: "datetime2", nullable: false), 18 | Data = table.Column(type: "nvarchar(max)", maxLength: 50000, nullable: false), 19 | Expiration = table.Column(type: "datetime2", nullable: true), 20 | SubjectId = table.Column(type: "nvarchar(200)", maxLength: 200, nullable: true), 21 | Type = table.Column(type: "nvarchar(50)", maxLength: 50, nullable: false) 22 | }, 23 | constraints: table => 24 | { 25 | table.PrimaryKey("PK_PersistedGrants", x => x.Key); 26 | }); 27 | 28 | migrationBuilder.CreateIndex( 29 | name: "IX_PersistedGrants_SubjectId_ClientId_Type", 30 | table: "PersistedGrants", 31 | columns: new[] { "SubjectId", "ClientId", "Type" }); 32 | } 33 | 34 | protected override void Down(MigrationBuilder migrationBuilder) 35 | { 36 | migrationBuilder.DropTable( 37 | name: "PersistedGrants"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /IdentityApp/Data/Migrations/IdentityServer/PersistedGrant/20180109123811_PersistedGrant21.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using IdentityServer4.EntityFramework.DbContexts; 3 | using Microsoft.EntityFrameworkCore; 4 | using Microsoft.EntityFrameworkCore.Infrastructure; 5 | using Microsoft.EntityFrameworkCore.Metadata; 6 | using Microsoft.EntityFrameworkCore.Migrations; 7 | using Microsoft.EntityFrameworkCore.Storage.Internal; 8 | using System; 9 | 10 | namespace IdentityApp.Data.Migrations.IdentityServer.PersistedGrant 11 | { 12 | [DbContext(typeof(PersistedGrantDbContext))] 13 | [Migration("20180109123811_PersistedGrant21")] 14 | partial class PersistedGrant21 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "2.0.1-rtm-125") 21 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 22 | 23 | modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => 24 | { 25 | b.Property("Key") 26 | .HasMaxLength(200); 27 | 28 | b.Property("ClientId") 29 | .IsRequired() 30 | .HasMaxLength(200); 31 | 32 | b.Property("CreationTime"); 33 | 34 | b.Property("Data") 35 | .IsRequired() 36 | .HasMaxLength(50000); 37 | 38 | b.Property("Expiration"); 39 | 40 | b.Property("SubjectId") 41 | .HasMaxLength(200); 42 | 43 | b.Property("Type") 44 | .IsRequired() 45 | .HasMaxLength(50); 46 | 47 | b.HasKey("Key"); 48 | 49 | b.HasIndex("SubjectId", "ClientId", "Type"); 50 | 51 | b.ToTable("PersistedGrants"); 52 | }); 53 | #pragma warning restore 612, 618 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /IdentityApp/Data/Migrations/IdentityServer/PersistedGrant/20180109123811_PersistedGrant21.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace IdentityApp.Data.Migrations.IdentityServer.PersistedGrant 6 | { 7 | public partial class PersistedGrant21 : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | 12 | } 13 | 14 | protected override void Down(MigrationBuilder migrationBuilder) 15 | { 16 | 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /IdentityApp/Data/Migrations/IdentityServer/PersistedGrant/20181213122026_IDPackageUpdateDec2018Persited.Designer.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using IdentityServer4.EntityFramework.DbContexts; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Migrations; 8 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 9 | 10 | namespace IdentityApp.Data.Migrations.IdentityServer.PersistedGrant 11 | { 12 | [DbContext(typeof(PersistedGrantDbContext))] 13 | [Migration("20181213122026_IDPackageUpdateDec2018Persited")] 14 | partial class IDPackageUpdateDec2018Persited 15 | { 16 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 17 | { 18 | #pragma warning disable 612, 618 19 | modelBuilder 20 | .HasAnnotation("ProductVersion", "2.2.0-rtm-35687") 21 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 22 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 23 | 24 | modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => 25 | { 26 | b.Property("UserCode") 27 | .ValueGeneratedOnAdd() 28 | .HasMaxLength(200); 29 | 30 | b.Property("ClientId") 31 | .IsRequired() 32 | .HasMaxLength(200); 33 | 34 | b.Property("CreationTime"); 35 | 36 | b.Property("Data") 37 | .IsRequired() 38 | .HasMaxLength(50000); 39 | 40 | b.Property("DeviceCode") 41 | .IsRequired() 42 | .HasMaxLength(200); 43 | 44 | b.Property("Expiration") 45 | .IsRequired(); 46 | 47 | b.Property("SubjectId") 48 | .HasMaxLength(200); 49 | 50 | b.HasKey("UserCode"); 51 | 52 | b.HasIndex("DeviceCode") 53 | .IsUnique(); 54 | 55 | b.ToTable("DeviceCodes"); 56 | }); 57 | 58 | modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => 59 | { 60 | b.Property("Key") 61 | .HasMaxLength(200); 62 | 63 | b.Property("ClientId") 64 | .IsRequired() 65 | .HasMaxLength(200); 66 | 67 | b.Property("CreationTime"); 68 | 69 | b.Property("Data") 70 | .IsRequired() 71 | .HasMaxLength(50000); 72 | 73 | b.Property("Expiration"); 74 | 75 | b.Property("SubjectId") 76 | .HasMaxLength(200); 77 | 78 | b.Property("Type") 79 | .IsRequired() 80 | .HasMaxLength(50); 81 | 82 | b.HasKey("Key"); 83 | 84 | b.HasIndex("SubjectId", "ClientId", "Type"); 85 | 86 | b.ToTable("PersistedGrants"); 87 | }); 88 | #pragma warning restore 612, 618 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /IdentityApp/Data/Migrations/IdentityServer/PersistedGrant/20181213122026_IDPackageUpdateDec2018Persited.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace IdentityApp.Data.Migrations.IdentityServer.PersistedGrant 5 | { 6 | public partial class IDPackageUpdateDec2018Persited : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | name: "DeviceCodes", 12 | columns: table => new 13 | { 14 | UserCode = table.Column(maxLength: 200, nullable: false), 15 | DeviceCode = table.Column(maxLength: 200, nullable: false), 16 | SubjectId = table.Column(maxLength: 200, nullable: true), 17 | ClientId = table.Column(maxLength: 200, nullable: false), 18 | CreationTime = table.Column(nullable: false), 19 | Expiration = table.Column(nullable: false), 20 | Data = table.Column(maxLength: 50000, nullable: false) 21 | }, 22 | constraints: table => 23 | { 24 | table.PrimaryKey("PK_DeviceCodes", x => x.UserCode); 25 | }); 26 | 27 | migrationBuilder.CreateIndex( 28 | name: "IX_DeviceCodes_DeviceCode", 29 | table: "DeviceCodes", 30 | column: "DeviceCode", 31 | unique: true); 32 | } 33 | 34 | protected override void Down(MigrationBuilder migrationBuilder) 35 | { 36 | migrationBuilder.DropTable( 37 | name: "DeviceCodes"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /IdentityApp/Data/Migrations/IdentityServer/PersistedGrant/PersistedGrantDbContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | // 2 | using System; 3 | using IdentityServer4.EntityFramework.DbContexts; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.EntityFrameworkCore.Infrastructure; 6 | using Microsoft.EntityFrameworkCore.Metadata; 7 | using Microsoft.EntityFrameworkCore.Storage.ValueConversion; 8 | 9 | namespace IdentityApp.Data.Migrations.IdentityServer.PersistedGrant 10 | { 11 | [DbContext(typeof(PersistedGrantDbContext))] 12 | partial class PersistedGrantDbContextModelSnapshot : ModelSnapshot 13 | { 14 | protected override void BuildModel(ModelBuilder modelBuilder) 15 | { 16 | #pragma warning disable 612, 618 17 | modelBuilder 18 | .HasAnnotation("ProductVersion", "2.2.0-rtm-35687") 19 | .HasAnnotation("Relational:MaxIdentifierLength", 128) 20 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 21 | 22 | modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b => 23 | { 24 | b.Property("UserCode") 25 | .ValueGeneratedOnAdd() 26 | .HasMaxLength(200); 27 | 28 | b.Property("ClientId") 29 | .IsRequired() 30 | .HasMaxLength(200); 31 | 32 | b.Property("CreationTime"); 33 | 34 | b.Property("Data") 35 | .IsRequired() 36 | .HasMaxLength(50000); 37 | 38 | b.Property("DeviceCode") 39 | .IsRequired() 40 | .HasMaxLength(200); 41 | 42 | b.Property("Expiration") 43 | .IsRequired(); 44 | 45 | b.Property("SubjectId") 46 | .HasMaxLength(200); 47 | 48 | b.HasKey("UserCode"); 49 | 50 | b.HasIndex("DeviceCode") 51 | .IsUnique(); 52 | 53 | b.ToTable("DeviceCodes"); 54 | }); 55 | 56 | modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b => 57 | { 58 | b.Property("Key") 59 | .HasMaxLength(200); 60 | 61 | b.Property("ClientId") 62 | .IsRequired() 63 | .HasMaxLength(200); 64 | 65 | b.Property("CreationTime"); 66 | 67 | b.Property("Data") 68 | .IsRequired() 69 | .HasMaxLength(50000); 70 | 71 | b.Property("Expiration"); 72 | 73 | b.Property("SubjectId") 74 | .HasMaxLength(200); 75 | 76 | b.Property("Type") 77 | .IsRequired() 78 | .HasMaxLength(50); 79 | 80 | b.HasKey("Key"); 81 | 82 | b.HasIndex("SubjectId", "ClientId", "Type"); 83 | 84 | b.ToTable("PersistedGrants"); 85 | }); 86 | #pragma warning restore 612, 618 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /IdentityApp/Extensions/EmailSenderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text.Encodings.Web; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Services 8 | { 9 | public static class EmailSenderExtensions 10 | { 11 | public static Task SendEmailConfirmationAsync(this IEmailSender emailSender, string email, string link) 12 | { 13 | return emailSender.SendEmailAsync(email, "Confirm your email", 14 | $"Please confirm your account by clicking this link: link"); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /IdentityApp/Extensions/UrlHelperExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using IdentityApp.Controllers; 6 | 7 | namespace Microsoft.AspNetCore.Mvc 8 | { 9 | public static class UrlHelperExtensions 10 | { 11 | public static string EmailConfirmationLink(this IUrlHelper urlHelper, string userId, string code, string scheme) 12 | { 13 | return urlHelper.Action( 14 | action: nameof(AccountController.ConfirmEmail), 15 | controller: "Account", 16 | values: new { userId, code }, 17 | protocol: scheme); 18 | } 19 | 20 | public static string ResetPasswordCallbackLink(this IUrlHelper urlHelper, string userId, string code, string scheme) 21 | { 22 | return urlHelper.Action( 23 | action: nameof(AccountController.ResetPassword), 24 | controller: "Account", 25 | values: new { userId, code }, 26 | protocol: scheme); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /IdentityApp/IdentityApp.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | netcoreapp2.2 4 | InProcess 5 | 6 | 7 | aspnet-IdentityApp-77a69134-7ece-4481-86db-b56de2a12985 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /IdentityApp/Models/AccountViewModels/ExternalLoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.AccountViewModels 8 | { 9 | public class ExternalLoginViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | public string Email { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /IdentityApp/Models/AccountViewModels/ForgotPasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.AccountViewModels 8 | { 9 | public class ForgotPasswordViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | public string Email { get; set; } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /IdentityApp/Models/AccountViewModels/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.AccountViewModels 8 | { 9 | public class LoginViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | public string Email { get; set; } 14 | 15 | [Required] 16 | [DataType(DataType.Password)] 17 | public string Password { get; set; } 18 | 19 | [Display(Name = "Remember me?")] 20 | public bool RememberMe { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /IdentityApp/Models/AccountViewModels/LoginWith2faViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.AccountViewModels 8 | { 9 | public class LoginWith2faViewModel 10 | { 11 | [Required] 12 | [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 13 | [DataType(DataType.Text)] 14 | [Display(Name = "Authenticator code")] 15 | public string TwoFactorCode { get; set; } 16 | 17 | [Display(Name = "Remember this machine")] 18 | public bool RememberMachine { get; set; } 19 | 20 | public bool RememberMe { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /IdentityApp/Models/AccountViewModels/LoginWithRecoveryCodeViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.AccountViewModels 8 | { 9 | public class LoginWithRecoveryCodeViewModel 10 | { 11 | [Required] 12 | [DataType(DataType.Text)] 13 | [Display(Name = "Recovery Code")] 14 | public string RecoveryCode { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /IdentityApp/Models/AccountViewModels/RegisterViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.AccountViewModels 8 | { 9 | public class RegisterViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | [Display(Name = "Email")] 14 | public string Email { get; set; } 15 | 16 | [Required] 17 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 18 | [DataType(DataType.Password)] 19 | [Display(Name = "Password")] 20 | public string Password { get; set; } 21 | 22 | [DataType(DataType.Password)] 23 | [Display(Name = "Confirm password")] 24 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 25 | public string ConfirmPassword { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /IdentityApp/Models/AccountViewModels/ResetPasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.AccountViewModels 8 | { 9 | public class ResetPasswordViewModel 10 | { 11 | [Required] 12 | [EmailAddress] 13 | public string Email { get; set; } 14 | 15 | [Required] 16 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 17 | [DataType(DataType.Password)] 18 | public string Password { get; set; } 19 | 20 | [DataType(DataType.Password)] 21 | [Display(Name = "Confirm password")] 22 | [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")] 23 | public string ConfirmPassword { get; set; } 24 | 25 | public string Code { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /IdentityApp/Models/ApplicationUser.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Identity; 6 | 7 | namespace IdentityApp.Models 8 | { 9 | // Add profile data for application users by adding properties to the ApplicationUser class 10 | public class ApplicationUser : IdentityUser 11 | { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IdentityApp/Models/ManageViewModels/ChangePasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.ManageViewModels 8 | { 9 | public class ChangePasswordViewModel 10 | { 11 | [Required] 12 | [DataType(DataType.Password)] 13 | [Display(Name = "Current password")] 14 | public string OldPassword { get; set; } 15 | 16 | [Required] 17 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 18 | [DataType(DataType.Password)] 19 | [Display(Name = "New password")] 20 | public string NewPassword { get; set; } 21 | 22 | [DataType(DataType.Password)] 23 | [Display(Name = "Confirm new password")] 24 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 25 | public string ConfirmPassword { get; set; } 26 | 27 | public string StatusMessage { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /IdentityApp/Models/ManageViewModels/EnableAuthenticatorViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.ComponentModel.DataAnnotations; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | 8 | namespace IdentityApp.Models.ManageViewModels 9 | { 10 | public class EnableAuthenticatorViewModel 11 | { 12 | [Required] 13 | [StringLength(7, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 14 | [DataType(DataType.Text)] 15 | [Display(Name = "Verification Code")] 16 | public string Code { get; set; } 17 | 18 | [ReadOnly(true)] 19 | public string SharedKey { get; set; } 20 | 21 | public string AuthenticatorUri { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /IdentityApp/Models/ManageViewModels/ExternalLoginsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Authentication; 6 | using Microsoft.AspNetCore.Identity; 7 | 8 | namespace IdentityApp.Models.ManageViewModels 9 | { 10 | public class ExternalLoginsViewModel 11 | { 12 | public IList CurrentLogins { get; set; } 13 | 14 | public IList OtherLogins { get; set; } 15 | 16 | public bool ShowRemoveButton { get; set; } 17 | 18 | public string StatusMessage { get; set; } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /IdentityApp/Models/ManageViewModels/GenerateRecoveryCodesViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.ManageViewModels 8 | { 9 | public class GenerateRecoveryCodesViewModel 10 | { 11 | public string[] RecoveryCodes { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /IdentityApp/Models/ManageViewModels/IndexViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.ManageViewModels 8 | { 9 | public class IndexViewModel 10 | { 11 | public string Username { get; set; } 12 | 13 | public bool IsEmailConfirmed { get; set; } 14 | 15 | [Required] 16 | [EmailAddress] 17 | public string Email { get; set; } 18 | 19 | [Phone] 20 | [Display(Name = "Phone number")] 21 | public string PhoneNumber { get; set; } 22 | 23 | public string StatusMessage { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /IdentityApp/Models/ManageViewModels/RemoveLoginViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.ManageViewModels 8 | { 9 | public class RemoveLoginViewModel 10 | { 11 | public string LoginProvider { get; set; } 12 | public string ProviderKey { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /IdentityApp/Models/ManageViewModels/SetPasswordViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.ManageViewModels 8 | { 9 | public class SetPasswordViewModel 10 | { 11 | [Required] 12 | [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)] 13 | [DataType(DataType.Password)] 14 | [Display(Name = "New password")] 15 | public string NewPassword { get; set; } 16 | 17 | [DataType(DataType.Password)] 18 | [Display(Name = "Confirm new password")] 19 | [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")] 20 | public string ConfirmPassword { get; set; } 21 | 22 | public string StatusMessage { get; set; } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /IdentityApp/Models/ManageViewModels/TwoFactorAuthenticationViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | 7 | namespace IdentityApp.Models.ManageViewModels 8 | { 9 | public class TwoFactorAuthenticationViewModel 10 | { 11 | public bool HasAuthenticator { get; set; } 12 | 13 | public int RecoveryCodesLeft { get; set; } 14 | 15 | public bool Is2faEnabled { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /IdentityApp/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using IdentityApp.Data.Migrations.IdentityServer; 3 | using Microsoft.AspNetCore; 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace IdentityApp 9 | { 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | var host = CreateWebHostBuilder(args).Build(); 15 | 16 | using (var scope = host.Services.CreateScope()) 17 | { 18 | var services = scope.ServiceProvider; 19 | 20 | try 21 | { 22 | IdentityServerDatabaseInitialization.InitializeDatabase(services); 23 | } 24 | catch (Exception ex) 25 | { 26 | var logger = services.GetRequiredService>(); 27 | logger.LogError(ex, "An error occurred Initializing the DB."); 28 | } 29 | } 30 | 31 | host.Run(); 32 | } 33 | 34 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 35 | WebHost.CreateDefaultBuilder(args) 36 | .UseStartup(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /IdentityApp/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:5000", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "environmentVariables": { 14 | "ASPNETCORE_ENVIRONMENT": "Development" 15 | } 16 | }, 17 | "IdentityApp": { 18 | "commandName": "IISExpress", 19 | "environmentVariables": { 20 | "ASPNETCORE_ENVIRONMENT": "Development" 21 | }, 22 | "applicationUrl": "http://localhost:5000" 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Account/AccountOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System; 6 | 7 | namespace IdentityServer4.Quickstart.UI 8 | { 9 | public class AccountOptions 10 | { 11 | public static bool ShowLogoutPrompt = true; 12 | public static bool AutomaticRedirectAfterSignOut = false; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Account/LoggedOutViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer4.Quickstart.UI 6 | { 7 | public class LoggedOutViewModel 8 | { 9 | public string PostLogoutRedirectUri { get; set; } 10 | public string ClientName { get; set; } 11 | public string SignOutIframeUrl { get; set; } 12 | 13 | public bool AutomaticRedirectAfterSignOut { get; set; } 14 | 15 | public string LogoutId { get; set; } 16 | public bool TriggerExternalSignout => ExternalAuthenticationScheme != null; 17 | public string ExternalAuthenticationScheme { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Account/LogoutInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer4.Quickstart.UI 6 | { 7 | public class LogoutInputModel 8 | { 9 | public string LogoutId { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Account/LogoutViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer4.Quickstart.UI 6 | { 7 | public class LogoutViewModel : LogoutInputModel 8 | { 9 | public bool ShowLogoutPrompt { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Consent/ConsentController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityServer4.Services; 6 | using IdentityServer4.Stores; 7 | using Microsoft.AspNetCore.Mvc; 8 | using Microsoft.Extensions.Logging; 9 | using System.Threading.Tasks; 10 | 11 | namespace IdentityServer4.Quickstart.UI 12 | { 13 | /// 14 | /// This controller processes the consent UI 15 | /// 16 | [SecurityHeaders] 17 | public class ConsentController : Controller 18 | { 19 | private readonly ConsentService _consent; 20 | 21 | public ConsentController( 22 | IIdentityServerInteractionService interaction, 23 | IClientStore clientStore, 24 | IResourceStore resourceStore, 25 | ILogger logger) 26 | { 27 | _consent = new ConsentService(interaction, clientStore, resourceStore, logger); 28 | } 29 | 30 | /// 31 | /// Shows the consent screen 32 | /// 33 | /// 34 | /// 35 | [HttpGet] 36 | public async Task Index(string returnUrl) 37 | { 38 | var vm = await _consent.BuildViewModelAsync(returnUrl); 39 | if (vm != null) 40 | { 41 | return View("Index", vm); 42 | } 43 | 44 | return View("Error"); 45 | } 46 | 47 | /// 48 | /// Handles the consent screen postback 49 | /// 50 | [HttpPost] 51 | [ValidateAntiForgeryToken] 52 | public async Task Index(ConsentInputModel model) 53 | { 54 | var result = await _consent.ProcessConsent(model); 55 | 56 | if (result.IsRedirect) 57 | { 58 | return Redirect(result.RedirectUri); 59 | } 60 | 61 | if (result.HasValidationError) 62 | { 63 | ModelState.AddModelError("", result.ValidationError); 64 | } 65 | 66 | if (result.ShowView) 67 | { 68 | return View("Index", result.ViewModel); 69 | } 70 | 71 | return View("Error"); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Consent/ConsentInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace IdentityServer4.Quickstart.UI 8 | { 9 | public class ConsentInputModel 10 | { 11 | public string Button { get; set; } 12 | public IEnumerable ScopesConsented { get; set; } 13 | public bool RememberConsent { get; set; } 14 | public string ReturnUrl { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Consent/ConsentOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer4.Quickstart.UI 6 | { 7 | public class ConsentOptions 8 | { 9 | public static bool EnableOfflineAccess = true; 10 | public static string OfflineAccessDisplayName = "Offline Access"; 11 | public static string OfflineAccessDescription = "Access to your applications and resources, even when you are offline"; 12 | 13 | public static readonly string MustChooseOneErrorMessage = "You must pick at least one permission"; 14 | public static readonly string InvalidSelectionErrorMessage = "Invalid selection"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Consent/ConsentViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace IdentityServer4.Quickstart.UI 8 | { 9 | public class ConsentViewModel : ConsentInputModel 10 | { 11 | public string ClientName { get; set; } 12 | public string ClientUrl { get; set; } 13 | public string ClientLogoUrl { get; set; } 14 | public bool AllowRememberConsent { get; set; } 15 | 16 | public IEnumerable IdentityScopes { get; set; } 17 | public IEnumerable ResourceScopes { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Consent/ProcessConsentResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer4.Quickstart.UI 6 | { 7 | public class ProcessConsentResult 8 | { 9 | public bool IsRedirect => RedirectUri != null; 10 | public string RedirectUri { get; set; } 11 | 12 | public bool ShowView => ViewModel != null; 13 | public ConsentViewModel ViewModel { get; set; } 14 | 15 | public bool HasValidationError => ValidationError != null; 16 | public string ValidationError { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Consent/ScopeViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer4.Quickstart.UI 6 | { 7 | public class ScopeViewModel 8 | { 9 | public string Name { get; set; } 10 | public string DisplayName { get; set; } 11 | public string Description { get; set; } 12 | public bool Emphasize { get; set; } 13 | public bool Required { get; set; } 14 | public bool Checked { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Grants/GrantsController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityServer4.Services; 6 | using IdentityServer4.Stores; 7 | using Microsoft.AspNetCore.Mvc; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Threading.Tasks; 11 | using Microsoft.AspNetCore.Authorization; 12 | 13 | namespace IdentityServer4.Quickstart.UI 14 | { 15 | /// 16 | /// This sample controller allows a user to revoke grants given to clients 17 | /// 18 | [SecurityHeaders] 19 | [Authorize(AuthenticationSchemes = IdentityServer4.IdentityServerConstants.DefaultCookieAuthenticationScheme)] 20 | public class GrantsController : Controller 21 | { 22 | private readonly IIdentityServerInteractionService _interaction; 23 | private readonly IClientStore _clients; 24 | private readonly IResourceStore _resources; 25 | 26 | public GrantsController(IIdentityServerInteractionService interaction, 27 | IClientStore clients, 28 | IResourceStore resources) 29 | { 30 | _interaction = interaction; 31 | _clients = clients; 32 | _resources = resources; 33 | } 34 | 35 | /// 36 | /// Show list of grants 37 | /// 38 | [HttpGet] 39 | public async Task Index() 40 | { 41 | return View("Index", await BuildViewModelAsync()); 42 | } 43 | 44 | /// 45 | /// Handle postback to revoke a client 46 | /// 47 | [HttpPost] 48 | [ValidateAntiForgeryToken] 49 | public async Task Revoke(string clientId) 50 | { 51 | await _interaction.RevokeUserConsentAsync(clientId); 52 | return RedirectToAction("Index"); 53 | } 54 | 55 | private async Task BuildViewModelAsync() 56 | { 57 | var grants = await _interaction.GetAllUserConsentsAsync(); 58 | 59 | var list = new List(); 60 | foreach(var grant in grants) 61 | { 62 | var client = await _clients.FindClientByIdAsync(grant.ClientId); 63 | if (client != null) 64 | { 65 | var resources = await _resources.FindResourcesByScopeAsync(grant.Scopes); 66 | 67 | var item = new GrantViewModel() 68 | { 69 | ClientId = client.ClientId, 70 | ClientName = client.ClientName ?? client.ClientId, 71 | ClientLogoUrl = client.LogoUri, 72 | ClientUrl = client.ClientUri, 73 | Created = grant.CreationTime, 74 | Expires = grant.Expiration, 75 | IdentityGrantNames = resources.IdentityResources.Select(x => x.DisplayName ?? x.Name).ToArray(), 76 | ApiGrantNames = resources.ApiResources.Select(x => x.DisplayName ?? x.Name).ToArray() 77 | }; 78 | 79 | list.Add(item); 80 | } 81 | } 82 | 83 | return new GrantsViewModel 84 | { 85 | Grants = list 86 | }; 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Grants/GrantsViewModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace IdentityServer4.Quickstart.UI 5 | { 6 | public class GrantsViewModel 7 | { 8 | public IEnumerable Grants { get; set; } 9 | } 10 | 11 | public class GrantViewModel 12 | { 13 | public string ClientId { get; set; } 14 | public string ClientName { get; set; } 15 | public string ClientUrl { get; set; } 16 | public string ClientLogoUrl { get; set; } 17 | public DateTime Created { get; set; } 18 | public DateTime? Expires { get; set; } 19 | public IEnumerable IdentityGrantNames { get; set; } 20 | public IEnumerable ApiGrantNames { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /IdentityApp/Quickstart/Home/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityServer4.Models; 6 | 7 | namespace IdentityServer4.Quickstart.UI 8 | { 9 | public class ErrorViewModel 10 | { 11 | public ErrorMessage Error { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /IdentityApp/Quickstart/SecurityHeadersAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.Filters; 7 | 8 | namespace IdentityServer4.Quickstart.UI 9 | { 10 | public class SecurityHeadersAttribute : ActionFilterAttribute 11 | { 12 | public override void OnResultExecuting(ResultExecutingContext context) 13 | { 14 | var result = context.Result; 15 | if (result is ViewResult) 16 | { 17 | if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Type-Options")) 18 | { 19 | context.HttpContext.Response.Headers.Add("X-Content-Type-Options", "nosniff"); 20 | } 21 | if (!context.HttpContext.Response.Headers.ContainsKey("X-Frame-Options")) 22 | { 23 | context.HttpContext.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN"); 24 | } 25 | 26 | var csp = "default-src 'self';"; 27 | // an example if you need client images to be displayed from twitter 28 | //var csp = "default-src 'self'; img-src 'self' https://pbs.twimg.com"; 29 | 30 | // once for standards compliant browsers 31 | if (!context.HttpContext.Response.Headers.ContainsKey("Content-Security-Policy")) 32 | { 33 | context.HttpContext.Response.Headers.Add("Content-Security-Policy", csp); 34 | } 35 | // and once again for IE 36 | if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Security-Policy")) 37 | { 38 | context.HttpContext.Response.Headers.Add("X-Content-Security-Policy", csp); 39 | } 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /IdentityApp/Services/EmailSender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace IdentityApp.Services 7 | { 8 | // This class is used by the application to send email for account confirmation and password reset. 9 | // For more details see https://go.microsoft.com/fwlink/?LinkID=532713 10 | public class EmailSender : IEmailSender 11 | { 12 | public Task SendEmailAsync(string email, string subject, string message) 13 | { 14 | return Task.CompletedTask; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /IdentityApp/Services/IEmailSender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace IdentityApp.Services 7 | { 8 | public interface IEmailSender 9 | { 10 | Task SendEmailAsync(string email, string subject, string message); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /IdentityApp/Services/ISmsSender.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace IdentityApp.Services 4 | { 5 | public interface ISmsSender 6 | { 7 | Task SendSmsAsync(string number, string message); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /IdentityApp/Services/MessageServices.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using System.Threading.Tasks; 3 | 4 | namespace IdentityApp.Services 5 | { 6 | // This class is used by the application to send Email and SMS 7 | // when you turn on two-factor authentication in ASP.NET Identity. 8 | // For more details see this link http://go.microsoft.com/fwlink/?LinkID=532713 9 | public class AuthMessageSender : IEmailSender, ISmsSender 10 | { 11 | private readonly ILogger _logger; 12 | 13 | public AuthMessageSender(ILogger logger) 14 | { 15 | _logger = logger; 16 | } 17 | public Task SendEmailAsync(string email, string subject, string message) 18 | { 19 | // Plug in your email service here to send an email. 20 | _logger.LogInformation("Email: {email}, Subject: {subject}, Message: {message}", email, subject, message); 21 | return Task.FromResult(0); 22 | } 23 | 24 | public Task SendSmsAsync(string number, string message) 25 | { 26 | // Plug in your SMS service here to send a text message. 27 | _logger.LogInformation("SMS: {number}, Message: {message}", number, message); 28 | return Task.FromResult(0); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /IdentityApp/Startup.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.EntityFrameworkCore; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Logging; 8 | using IdentityApp.Data; 9 | using IdentityApp.Models; 10 | using IdentityApp.Services; 11 | using Microsoft.AspNetCore.Identity; 12 | using Microsoft.AspNetCore.Mvc; 13 | 14 | namespace IdentityApp 15 | { 16 | public class Startup 17 | { 18 | public IConfiguration Configuration { get; } 19 | 20 | public Startup(IConfiguration configuration) 21 | { 22 | Configuration = configuration; 23 | } 24 | 25 | 26 | // This method gets called by the runtime. Use this method to add services to the container. 27 | public void ConfigureServices(IServiceCollection services) 28 | { 29 | // Add framework services. 30 | services.AddDbContext(options => 31 | options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))); 32 | 33 | services.AddIdentity() 34 | .AddEntityFrameworkStores() 35 | .AddDefaultTokenProviders(); 36 | 37 | services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 38 | 39 | // Add application services. 40 | services.AddTransient(); 41 | services.AddTransient(); 42 | 43 | var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; 44 | 45 | services.AddIdentityServer() 46 | .AddDeveloperSigningCredential() 47 | .AddAspNetIdentity() 48 | .AddConfigurationStore(options => 49 | { 50 | options.ConfigureDbContext = builder => 51 | builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), 52 | db => db.MigrationsAssembly(migrationsAssembly)); 53 | }) 54 | .AddOperationalStore(options => 55 | { 56 | options.ConfigureDbContext = builder => 57 | builder.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"), 58 | db => db.MigrationsAssembly(migrationsAssembly)); 59 | }); 60 | 61 | services.AddAuthentication().AddTwitter(twitterOptions => 62 | { 63 | twitterOptions.ConsumerKey = Configuration["Authentication:Twitter:ConsumerKey"]; 64 | twitterOptions.ConsumerSecret = Configuration["Authentication:Twitter:ConsumerSecret"]; 65 | }); 66 | } 67 | 68 | // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 69 | public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 70 | { 71 | loggerFactory.AddConsole(Configuration.GetSection("Logging")); 72 | loggerFactory.AddDebug(); 73 | 74 | if (env.IsDevelopment()) 75 | { 76 | app.UseDeveloperExceptionPage(); 77 | app.UseDatabaseErrorPage(); 78 | } 79 | else 80 | { 81 | app.UseExceptionHandler("/Home/Error"); 82 | } 83 | 84 | app.UseStaticFiles(); 85 | 86 | app.UseIdentityServer(); 87 | 88 | app.UseMvc(routes => 89 | { 90 | routes.MapRoute( 91 | name: "default", 92 | template: "{controller=Home}/{action=Index}/{id?}"); 93 | }); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/AccessDenied.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Access denied"; 3 | } 4 | 5 |
6 |

ViewData["Title"]

7 |

You do not have access to this resource.

8 |
9 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/ConfirmEmail.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Confirm email"; 3 | } 4 | 5 |

@ViewData["Title"]

6 |
7 |

8 | Thank you for confirming your email. 9 |

10 |
11 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/ExternalLogin.cshtml: -------------------------------------------------------------------------------- 1 | @model ExternalLoginViewModel 2 | @{ 3 | ViewData["Title"] = "Register"; 4 | } 5 | 6 |

@ViewData["Title"]

7 |

Associate your @ViewData["LoginProvider"] account.

8 |
9 | 10 |

11 | You've successfully authenticated with @ViewData["LoginProvider"]. 12 | Please enter an email address for this site below and click the Register button to finish 13 | logging in. 14 |

15 | 16 |
17 |
18 |
19 |
20 |
21 | 22 | 23 | 24 |
25 | 26 |
27 |
28 |
29 | 30 | @section Scripts { 31 | @await Html.PartialAsync("_ValidationScriptsPartial") 32 | } 33 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/ForgotPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ForgotPasswordViewModel 2 | @{ 3 | ViewData["Title"] = "Forgot your password?"; 4 | } 5 | 6 |

@ViewData["Title"]

7 |

Enter your email.

8 |
9 |
10 |
11 |
12 |
13 |
14 | 15 | 16 | 17 |
18 | 19 |
20 |
21 |
22 | 23 | @section Scripts { 24 | @await Html.PartialAsync("_ValidationScriptsPartial") 25 | } 26 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/ForgotPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Forgot password confirmation"; 3 | } 4 | 5 |

@ViewData["Title"]

6 |

7 | Please check your email to reset your password. 8 |

9 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/Lockout.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Locked out"; 3 | } 4 | 5 |
6 |

@ViewData["Title"]

7 |

This account has been locked out, please try again later.

8 |
9 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/LoggedOut.cshtml: -------------------------------------------------------------------------------- 1 | @model LoggedOutViewModel 2 | 3 | @{ 4 | // set this so the layout rendering sees an anonymous user 5 | ViewData["signed-out"] = true; 6 | } 7 | 8 | 27 | 28 | @section scripts 29 | { 30 | @if (Model.AutomaticRedirectAfterSignOut) 31 | { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/Login.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Collections.Generic 2 | @using System.Linq 3 | @using Microsoft.AspNetCore.Http 4 | @using Microsoft.AspNetCore.Http.Authentication 5 | @model LoginViewModel 6 | @inject SignInManager SignInManager 7 | 8 | @{ 9 | ViewData["Title"] = "Log in"; 10 | } 11 | 12 |

@ViewData["Title"]

13 |
14 |
15 |
16 |
17 |

Use a local account to log in.

18 |
19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 | 28 | 29 |
30 |
31 |
32 | 36 |
37 |
38 |
39 | 40 |
41 |
42 |

43 | Forgot your password? 44 |

45 |

46 | Register as a new user? 47 |

48 |
49 |
50 |
51 |
52 |
53 |
54 |

Use another service to log in.

55 |
56 | @{ 57 | var loginProviders = (await SignInManager.GetExternalAuthenticationSchemesAsync()).ToList(); 58 | if (loginProviders.Count == 0) 59 | { 60 |
61 |

62 | There are no external authentication services configured. See this article 63 | for details on setting up this ASP.NET application to support logging in via external services. 64 |

65 |
66 | } 67 | else 68 | { 69 |
70 |
71 |

72 | @foreach (var provider in loginProviders) 73 | { 74 | 75 | } 76 |

77 |
78 |
79 | } 80 | } 81 |
82 |
83 |
84 | 85 | @section Scripts { 86 | @await Html.PartialAsync("_ValidationScriptsPartial") 87 | } 88 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/LoginWith2fa.cshtml: -------------------------------------------------------------------------------- 1 | @model LoginWith2faViewModel 2 | @{ 3 | ViewData["Title"] = "Two-factor authentication"; 4 | } 5 | 6 |

@ViewData["Title"]

7 |
8 |

Your login is protected with an authenticator app. Enter your authenticator code below.

9 |
10 |
11 |
12 | 13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 |
21 | 25 |
26 |
27 |
28 | 29 |
30 |
31 |
32 |
33 |

34 | Don't have access to your authenticator device? You can 35 | log in with a recovery code. 36 |

37 | 38 | @section Scripts { 39 | @await Html.PartialAsync("_ValidationScriptsPartial") 40 | } -------------------------------------------------------------------------------- /IdentityApp/Views/Account/LoginWithRecoveryCode.cshtml: -------------------------------------------------------------------------------- 1 | @model LoginWithRecoveryCodeViewModel 2 | @{ 3 | ViewData["Title"] = "Recovery code verification"; 4 | } 5 | 6 |

@ViewData["Title"]

7 |
8 |

9 | You have requested to login with a recovery code. This login will not be remembered until you provide 10 | an authenticator app code at login or disable 2FA and login again. 11 |

12 |
13 |
14 |
15 |
16 |
17 | 18 | 19 | 20 |
21 | 22 |
23 |
24 |
25 | 26 | @section Scripts { 27 | @await Html.PartialAsync("_ValidationScriptsPartial") 28 | } -------------------------------------------------------------------------------- /IdentityApp/Views/Account/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @model LogoutViewModel 2 | 3 |
4 | 7 | 8 |
9 |
10 |

Would you like to logout of IdentityServer?

11 |
12 | 13 |
14 |
15 | 16 |
17 |
18 |
19 |
20 |
21 |
-------------------------------------------------------------------------------- /IdentityApp/Views/Account/Register.cshtml: -------------------------------------------------------------------------------- 1 | @model RegisterViewModel 2 | @{ 3 | ViewData["Title"] = "Register"; 4 | } 5 | 6 |

@ViewData["Title"]

7 | 8 |
9 |
10 |
11 |

Create a new account.

12 |
13 |
14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 |
29 | 30 |
31 |
32 |
33 | 34 | @section Scripts { 35 | @await Html.PartialAsync("_ValidationScriptsPartial") 36 | } 37 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/ResetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ResetPasswordViewModel 2 | @{ 3 | ViewData["Title"] = "Reset password"; 4 | } 5 | 6 |

@ViewData["Title"]

7 |

Reset your password.

8 |
9 |
10 |
11 |
12 |
13 | 14 |
15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 23 |
24 |
25 | 26 | 27 | 28 |
29 | 30 |
31 |
32 |
33 | 34 | @section Scripts { 35 | @await Html.PartialAsync("_ValidationScriptsPartial") 36 | } 37 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/ResetPasswordConfirmation.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Reset password confirmation"; 3 | } 4 | 5 |

@ViewData["Title"]

6 |

7 | Your password has been reset. Please click here to log in. 8 |

9 | -------------------------------------------------------------------------------- /IdentityApp/Views/Account/SignedOut.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Signed out"; 3 | } 4 | 5 |

@ViewData["Title"]

6 |

7 | You have successfully signed out. 8 |

9 | -------------------------------------------------------------------------------- /IdentityApp/Views/Consent/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model ConsentViewModel 2 | 3 | -------------------------------------------------------------------------------- /IdentityApp/Views/Consent/_ScopeListItem.cshtml: -------------------------------------------------------------------------------- 1 | @model ScopeViewModel 2 | 3 |
  • 4 | 24 | @if (Model.Required) 25 | { 26 | (required) 27 | } 28 | @if (Model.Description != null) 29 | { 30 | 33 | } 34 |
  • -------------------------------------------------------------------------------- /IdentityApp/Views/Grants/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model GrantsViewModel 2 | 3 |
    4 | 12 | 13 | @if (Model.Grants.Any() == false) 14 | { 15 |
    16 |
    17 |
    18 | You have not given access to any applications 19 |
    20 |
    21 |
    22 | } 23 | else 24 | { 25 | foreach (var grant in Model.Grants) 26 | { 27 |
    28 |
    29 | @if (grant.ClientLogoUrl != null) 30 | { 31 | 32 | } 33 |
    34 |
    35 |
    @grant.ClientName
    36 |
    37 | Created: @grant.Created.ToString("yyyy-MM-dd") 38 |
    39 | @if (grant.Expires.HasValue) 40 | { 41 |
    42 | Expires: @grant.Expires.Value.ToString("yyyy-MM-dd") 43 |
    44 | } 45 | @if (grant.IdentityGrantNames.Any()) 46 | { 47 |
    48 |
    Identity Grants
    49 |
      50 | @foreach (var name in grant.IdentityGrantNames) 51 | { 52 |
    • @name
    • 53 | } 54 |
    55 |
    56 | } 57 | @if (grant.ApiGrantNames.Any()) 58 | { 59 |
    60 |
    API Grants
    61 |
      62 | @foreach (var name in grant.ApiGrantNames) 63 | { 64 |
    • @name
    • 65 | } 66 |
    67 |
    68 | } 69 |
    70 |
    71 |
    72 | 73 | 74 |
    75 |
    76 |
    77 | } 78 | } 79 |
    -------------------------------------------------------------------------------- /IdentityApp/Views/Home/About.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Authentication; 2 | @{ 3 | ViewData["Title"] = "About"; 4 | } 5 |

    @ViewData["Title"]

    6 |

    @ViewData["Message"]

    7 | 8 |

    User claims

    9 | 10 |
    11 | @foreach (var claim in User.Claims) 12 | { 13 |
    @claim.Type
    14 |
    @claim.Value
    15 | 16 | } 17 |
    id token
    18 |
    @await ViewContext.HttpContext.GetTokenAsync("id_token")
    19 |
    20 | -------------------------------------------------------------------------------- /IdentityApp/Views/Home/Contact.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Contact"; 3 | } 4 |

    @ViewData["Title"]

    5 |

    @ViewData["Message"]

    6 | 7 |
    8 | One Microsoft Way
    9 | Redmond, WA 98052-6399
    10 | P: 11 | 425.555.0100 12 |
    13 | 14 |
    15 | Support: Support@example.com
    16 | Marketing: Marketing@example.com 17 |
    18 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/ChangePassword.cshtml: -------------------------------------------------------------------------------- 1 | @model ChangePasswordViewModel 2 | @{ 3 | ViewData["Title"] = "Change password"; 4 | ViewData.AddActivePage(ManageNavPages.ChangePassword); 5 | } 6 | 7 |

    @ViewData["Title"]

    8 | @Html.Partial("_StatusMessage", Model.StatusMessage) 9 |
    10 |
    11 |
    12 |
    13 |
    14 | 15 | 16 | 17 |
    18 |
    19 | 20 | 21 | 22 |
    23 |
    24 | 25 | 26 | 27 |
    28 | 29 |
    30 |
    31 |
    32 | 33 | @section Scripts { 34 | @await Html.PartialAsync("_ValidationScriptsPartial") 35 | } 36 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/Disable2fa.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Disable two-factor authentication (2FA)"; 3 | ViewData.AddActivePage(ManageNavPages.TwoFactorAuthentication); 4 | } 5 | 6 |

    @ViewData["Title"]

    7 | 8 | 19 | 20 |
    21 |
    22 | 23 |
    24 |
    25 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/EnableAuthenticator.cshtml: -------------------------------------------------------------------------------- 1 | @model EnableAuthenticatorViewModel 2 | @{ 3 | ViewData["Title"] = "Enable authenticator"; 4 | ViewData.AddActivePage(ManageNavPages.TwoFactorAuthentication); 5 | } 6 | 7 |

    @ViewData["Title"]

    8 |
    9 |

    To use an authenticator app go through the following steps:

    10 |
      11 |
    1. 12 |

      13 | Download a two-factor authenticator app like Microsoft Authenticator for 14 | Windows Phone, 15 | Android and 16 | iOS or 17 | Google Authenticator for 18 | Android and 19 | iOS. 20 |

      21 |
    2. 22 |
    3. 23 |

      Scan the QR Code or enter this key @Model.SharedKey into your two factor authenticator app. Spaces and casing do not matter.

      24 |
      To enable QR code generation please read our documentation.
      25 |
      26 |
      27 |
    4. 28 |
    5. 29 |

      30 | Once you have scanned the QR code or input the key above, your two factor authentication app will provide you 31 | with a unique code. Enter the code in the confirmation box below. 32 |

      33 |
      34 |
      35 |
      36 |
      37 | 38 | 39 | 40 |
      41 | 42 |
      43 |
      44 |
      45 |
      46 |
    6. 47 |
    48 |
    49 | 50 | @section Scripts { 51 | @await Html.PartialAsync("_ValidationScriptsPartial") 52 | } 53 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/ExternalLogins.cshtml: -------------------------------------------------------------------------------- 1 | @model ExternalLoginsViewModel 2 | @{ 3 | ViewData["Title"] = "Manage your external logins"; 4 | ViewData.AddActivePage(ManageNavPages.ExternalLogins); 5 | } 6 | 7 | @Html.Partial("_StatusMessage", Model.StatusMessage) 8 | @if (Model.CurrentLogins?.Count > 0) 9 | { 10 |

    Registered Logins

    11 | 12 | 13 | @foreach (var login in Model.CurrentLogins) 14 | { 15 | 16 | 17 | 33 | 34 | } 35 | 36 |
    @login.LoginProvider 18 | @if (Model.ShowRemoveButton) 19 | { 20 |
    21 |
    22 | 23 | 24 | 25 |
    26 |
    27 | } 28 | else 29 | { 30 | @:   31 | } 32 |
    37 | } 38 | @if (Model.OtherLogins?.Count > 0) 39 | { 40 |

    Add another service to log in.

    41 |
    42 |
    43 |
    44 |

    45 | @foreach (var provider in Model.OtherLogins) 46 | { 47 | 48 | } 49 |

    50 |
    51 |
    52 | } 53 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/GenerateRecoveryCodes.cshtml: -------------------------------------------------------------------------------- 1 | @model GenerateRecoveryCodesViewModel 2 | @{ 3 | ViewData["Title"] = "Recovery codes"; 4 | ViewData.AddActivePage(ManageNavPages.TwoFactorAuthentication); 5 | } 6 | 7 |

    @ViewData["Title"]

    8 | 17 |
    18 |
    19 | @for (var row = 0; row < Model.RecoveryCodes.Count(); row += 2) 20 | { 21 | @Model.RecoveryCodes[row] @Model.RecoveryCodes[row + 1]
    22 | } 23 |
    24 |
    -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model IndexViewModel 2 | @{ 3 | ViewData["Title"] = "Profile"; 4 | ViewData.AddActivePage(ManageNavPages.Index); 5 | } 6 | 7 |

    @ViewData["Title"]

    8 | @Html.Partial("_StatusMessage", Model.StatusMessage) 9 |
    10 |
    11 |
    12 |
    13 |
    14 | 15 | 16 |
    17 |
    18 | 19 | @if (Model.IsEmailConfirmed) 20 | { 21 |
    22 | 23 | 24 |
    25 | } 26 | else 27 | { 28 | 29 | 30 | } 31 | 32 |
    33 |
    34 | 35 | 36 | 37 |
    38 | 39 |
    40 |
    41 |
    42 | 43 | @section Scripts { 44 | @await Html.PartialAsync("_ValidationScriptsPartial") 45 | } 46 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/ManageNavPages.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc.Rendering; 6 | using Microsoft.AspNetCore.Mvc.ViewFeatures; 7 | 8 | namespace IdentityApp.Views.Manage 9 | { 10 | public static class ManageNavPages 11 | { 12 | public static string ActivePageKey => "ActivePage"; 13 | 14 | public static string Index => "Index"; 15 | 16 | public static string ChangePassword => "ChangePassword"; 17 | 18 | public static string ExternalLogins => "ExternalLogins"; 19 | 20 | public static string TwoFactorAuthentication => "TwoFactorAuthentication"; 21 | 22 | public static string IndexNavClass(ViewContext viewContext) => PageNavClass(viewContext, Index); 23 | 24 | public static string ChangePasswordNavClass(ViewContext viewContext) => PageNavClass(viewContext, ChangePassword); 25 | 26 | public static string ExternalLoginsNavClass(ViewContext viewContext) => PageNavClass(viewContext, ExternalLogins); 27 | 28 | public static string TwoFactorAuthenticationNavClass(ViewContext viewContext) => PageNavClass(viewContext, TwoFactorAuthentication); 29 | 30 | public static string PageNavClass(ViewContext viewContext, string page) 31 | { 32 | var activePage = viewContext.ViewData["ActivePage"] as string; 33 | return string.Equals(activePage, page, StringComparison.OrdinalIgnoreCase) ? "active" : null; 34 | } 35 | 36 | public static void AddActivePage(this ViewDataDictionary viewData, string activePage) => viewData[ActivePageKey] = activePage; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/ResetAuthenticator.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewData["Title"] = "Reset authenticator key"; 3 | ViewData.AddActivePage(ManageNavPages.TwoFactorAuthentication); 4 | } 5 | 6 |

    @ViewData["Title"]

    7 | 17 |
    18 |
    19 | 20 |
    21 |
    -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/SetPassword.cshtml: -------------------------------------------------------------------------------- 1 | @model SetPasswordViewModel 2 | @{ 3 | ViewData["Title"] = "Set password"; 4 | ViewData.AddActivePage(ManageNavPages.ChangePassword); 5 | } 6 | 7 |

    Set your password

    8 | @Html.Partial("_StatusMessage", Model.StatusMessage) 9 |

    10 | You do not have a local username/password for this site. Add a local 11 | account so you can log in without an external login. 12 |

    13 |
    14 |
    15 |
    16 |
    17 |
    18 | 19 | 20 | 21 |
    22 |
    23 | 24 | 25 | 26 |
    27 | 28 |
    29 |
    30 |
    31 | 32 | @section Scripts { 33 | @await Html.PartialAsync("_ValidationScriptsPartial") 34 | } 35 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/TwoFactorAuthentication.cshtml: -------------------------------------------------------------------------------- 1 | @model TwoFactorAuthenticationViewModel 2 | @{ 3 | ViewData["Title"] = "Two-factor authentication"; 4 | ViewData.AddActivePage(ManageNavPages.TwoFactorAuthentication); 5 | } 6 | 7 |

    @ViewData["Title"]

    8 | @if (Model.Is2faEnabled) 9 | { 10 | if (Model.RecoveryCodesLeft == 0) 11 | { 12 |
    13 | You have no recovery codes left. 14 |

    You must generate a new set of recovery codes before you can log in with a recovery code.

    15 |
    16 | } 17 | else if (Model.RecoveryCodesLeft == 1) 18 | { 19 |
    20 | You have 1 recovery code left. 21 |

    You can generate a new set of recovery codes.

    22 |
    23 | } 24 | else if (Model.RecoveryCodesLeft <= 3) 25 | { 26 |
    27 | You have @Model.RecoveryCodesLeft recovery codes left. 28 |

    You should generate a new set of recovery codes.

    29 |
    30 | } 31 | 32 | Disable 2FA 33 | Reset recovery codes 34 | } 35 | 36 |
    Authenticator app
    37 | @if (!Model.HasAuthenticator) 38 | { 39 | Add authenticator app 40 | } 41 | else 42 | { 43 | Configure authenticator app 44 | Reset authenticator key 45 | } 46 | 47 | @section Scripts { 48 | @await Html.PartialAsync("_ValidationScriptsPartial") 49 | } 50 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "/Views/Shared/_Layout.cshtml"; 3 | } 4 | 5 |

    Manage your account

    6 | 7 |
    8 |

    Change your account settings

    9 |
    10 |
    11 |
    12 | @await Html.PartialAsync("_ManageNav") 13 |
    14 |
    15 | @RenderBody() 16 |
    17 |
    18 |
    19 | 20 | @section Scripts { 21 | @RenderSection("Scripts", required: false) 22 | } 23 | 24 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/_ManageNav.cshtml: -------------------------------------------------------------------------------- 1 | @using IdentityApp.Views.Manage 2 | @inject SignInManager SignInManager 3 | @{ 4 | var hasExternalLogins = (await SignInManager.GetExternalAuthenticationSchemesAsync()).Any(); 5 | } 6 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/_StatusMessage.cshtml: -------------------------------------------------------------------------------- 1 | @model string 2 | 3 | @if (!String.IsNullOrEmpty(Model)) 4 | { 5 | var statusMessageClass = Model.StartsWith("Error") ? "danger" : "success"; 6 | 10 | } 11 | -------------------------------------------------------------------------------- /IdentityApp/Views/Manage/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using IdentityApp.Views.Manage -------------------------------------------------------------------------------- /IdentityApp/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Hosting 2 | @model ErrorViewModel 3 | @inject IHostingEnvironment host 4 | 5 | @{ 6 | var error = Model?.Error?.Error; 7 | var errorDescription = host.IsDevelopment() ? Model?.Error?.ErrorDescription : null; 8 | var request_id = Model?.Error?.RequestId; 9 | } 10 | 11 |
    12 | 15 | 16 |
    17 |
    18 |
    19 | Sorry, there was an error 20 | 21 | @if (error != null) 22 | { 23 | 24 | 25 | : @error 26 | 27 | 28 | 29 | if (errorDescription != null) 30 | { 31 |
    @errorDescription
    32 | } 33 | } 34 |
    35 | 36 | @if (request_id != null) 37 | { 38 |
    Request Id: @request_id
    39 | } 40 |
    41 |
    42 |
    43 | -------------------------------------------------------------------------------- /IdentityApp/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | @ViewData["Title"] - IdentityApp 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | 19 | 20 | 41 |
    42 | @RenderBody() 43 |
    44 |
    45 |

    © 2017 - IdentityApp

    46 |
    47 |
    48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 61 | 67 | 68 | 69 | 70 | @RenderSection("Scripts", required: false) 71 | 72 | 73 | -------------------------------------------------------------------------------- /IdentityApp/Views/Shared/_LoginPartial.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using IdentityApp.Models 3 | 4 | @inject SignInManager SignInManager 5 | @inject UserManager UserManager 6 | 7 | @if (SignInManager.IsSignedIn(User)) 8 | { 9 | 19 | } 20 | else 21 | { 22 | 26 | } 27 | -------------------------------------------------------------------------------- /IdentityApp/Views/Shared/_ValidationScriptsPartial.cshtml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 12 | 18 | 19 | -------------------------------------------------------------------------------- /IdentityApp/Views/Shared/_ValidationSummary.cshtml: -------------------------------------------------------------------------------- 1 | @if (ViewContext.ModelState.IsValid == false) 2 | { 3 |
    4 | Error 5 |
    6 |
    7 | } -------------------------------------------------------------------------------- /IdentityApp/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using Microsoft.AspNetCore.Identity 2 | @using IdentityApp 3 | @using IdentityApp.Models 4 | @using IdentityApp.Models.AccountViewModels 5 | @using IdentityApp.Models.ManageViewModels 6 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 7 | @using IdentityServer4.Quickstart.UI -------------------------------------------------------------------------------- /IdentityApp/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /IdentityApp/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": false, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /IdentityApp/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ConnectionStrings": { 3 | "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-IdentityApp-7d0c7fee-d7aa-4566-8f10-993456e7a67a;Trusted_Connection=True;MultipleActiveResultSets=true" 4 | //"DefaultConnection": "Data Source=IdentityAppDb.db" 5 | }, 6 | "Logging": { 7 | "IncludeScopes": false, 8 | "LogLevel": { 9 | "Default": "Warning" 10 | } 11 | }, 12 | "ClientAddress": "http://localhost:5002" 13 | } 14 | -------------------------------------------------------------------------------- /IdentityApp/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "asp.net", 3 | "private": true, 4 | "dependencies": { 5 | "bootstrap": "3.3.7", 6 | "jquery": "2.2.0", 7 | "jquery-validation": "1.14.0", 8 | "jquery-validation-unobtrusive": "3.2.6" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /IdentityApp/bundleconfig.json: -------------------------------------------------------------------------------- 1 | // Configure bundling and minification for the project. 2 | // More info at https://go.microsoft.com/fwlink/?LinkId=808241 3 | [ 4 | { 5 | "outputFileName": "wwwroot/css/site.min.css", 6 | // An array of relative input file paths. Globbing patterns supported 7 | "inputFiles": [ 8 | "wwwroot/css/site.css" 9 | ] 10 | }, 11 | { 12 | "outputFileName": "wwwroot/js/site.min.js", 13 | "inputFiles": [ 14 | "wwwroot/js/site.js" 15 | ], 16 | // Optionally specify minification options 17 | "minify": { 18 | "enabled": true, 19 | "renameLocals": true 20 | }, 21 | // Optionally generate .map file 22 | "sourceMap": false 23 | } 24 | ] 25 | -------------------------------------------------------------------------------- /IdentityApp/tempkey.rsa: -------------------------------------------------------------------------------- 1 | {"KeyId":"972920cce4577a31a75c56930f12059c","Parameters":{"D":"OYE1Oyas7hj9hoev3f28PuRg8KrcHnrGnF3NoS6U8oV4NXrJzJTy7GKW/CNavtczg/DSg9NY1+MNj682xQUa1FqKvs3yY1A7mBXfVCufufAYL1YTkhn0b1eBgxNWrE5uaCKsKd3TVNqcvWt6Ed3pLQtjV5hZh9f6cnEiU4U8oixMuZbw7c1e10yXCVKc4fgdj63DP0OXoLxUYurzz+5ZdsmbkPeLvv6XdFKkGf3b0Q9C2mvptlliKwYiPJNv9+52K6okdCD8rLY0Gm9KWHWl++0hkVZV4d5LU1ZrCw2oiRRFmBNzQZwIt7Lgp92NqY0K2oGhS+Q22GlNEKmXIFPPQQ==","DP":"qHuvWz1WZhAj30dv1Jif39/q9JBwo1W0zVMRVvCqsUdbms5+sv5gP2+uA/XumuvvORoaXOgjAxpZyydk7W2vKlbRL8+VcJR1sWqeQX530N+WYUWNAxHfxUmBaEMUAiwE8f8Lngdrs8ZFwuwdpo3PFotx56PRfpBAXoeGy66fTpE=","DQ":"78WVcfL+GbeiH0A+griARbqmbZxD7yP4HHyaqcKrZBBSgg1EDkXEQQ+zDEjfrLrP4IDBxTxi0k5OlXOSxx0eZluBdSmjQ/WcHApi7EJdqrfuGYZpHmIrPSKzP4zh8uN+EZmkIaBiPeL/rzkXKvJZJ82ksfxP0CncS5bXqPhX7FU=","Exponent":"AQAB","InverseQ":"zA4O4LsY3cE2N3PwTXQgWXhFKEDxRA2F974SyPacgoYC53L0xwq79xfeoWao1K7n1allUWTAqHtdQw/glGmhBtozlQ9xQxMBq9WFFwBi1Pk6wkFtDrwgunUU09zu+1dulvJROTBlS/sLIC0WD3cxlKKnf6QrvoueWPSWoKFiurQ=","Modulus":"yuEc1dQC7qmA/FLGhyIZFyk7KdZIAvYlzcl0MHUrdCBXP4uQ+EPoNFWZq7DvficPlqk2TpQhOtEb0hd2PwGKmqTr18SzuXnr1CQLKdNK03Tk3uauv5R8fWiHT+M/uC/+/O2Ji0XcGHJ2E/VMegvWsnJx0aK+g6i2t52AnYp50WJaMx+t0Px5bLjrEGqge4qWY0y0UzMazSY8/RNzmVxfwe73tHdPodkEx+79PO6/yfJfPBmiwokRiRJuRmjQMNEXMAQE3OKM/kov3aGqF+ktjugVVJmjknpldznBhSqMuj4V1rF9J+7MbUi1sjMs1c+nmbNLiqZFUiF4GmElfwnWwQ==","P":"zvZ6t3jPdRJvUXjgAUTZO2INiJh/E+BU7PWq6BhEpP7LiTQi3LVuMoQw7AUAqBthQeCxdNKC87310MpMLp0jZHyBKgl34cyD7KeYG3gUV3rpArS3ONhcPSfqb2tZbXCy3zLZypSaSnq6rfoXWhJMkE6n/pGbDgT8MaIhy6quVps=","Q":"+vLybuRv3+fpQ7xz0zA6u7JfUsx4LTt7P0gGHACC+70kgG+/4KRkVoYxtqO6Me+um5HjKUajNxcR2TPuJ0NwNG+XzPVMcv+ub/a1CjfBdCeT8cqNbNGnWMwWrLS1SjEcwu2V1R/MUSpm4vfblO0J+dzXwvloq40WpZaVrex2L9M="}} -------------------------------------------------------------------------------- /IdentityApp/wwwroot/_references.js: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | /// 4 | /// 5 | /// 6 | /// 7 | /// 8 | -------------------------------------------------------------------------------- /IdentityApp/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 50px; 3 | padding-bottom: 20px; 4 | } 5 | 6 | /* Wrapping element */ 7 | /* Set some basic padding to keep content from hitting the edges */ 8 | .body-content { 9 | padding-left: 15px; 10 | padding-right: 15px; 11 | } 12 | 13 | /* Set widths on the form inputs since otherwise they're 100% wide */ 14 | input, 15 | select, 16 | textarea { 17 | max-width: 280px; 18 | } 19 | 20 | /* Carousel */ 21 | .carousel-caption p { 22 | font-size: 20px; 23 | line-height: 1.4; 24 | } 25 | 26 | /* buttons and links extension to use brackets: [ click me ] */ 27 | .btn-bracketed::before { 28 | display: inline-block; 29 | content: "["; 30 | padding-right: 0.5em; 31 | } 32 | 33 | .btn-bracketed::after { 34 | display: inline-block; 35 | content: "]"; 36 | padding-left: 0.5em; 37 | } 38 | 39 | /* Make .svg files in the carousel display properly in older browsers */ 40 | .carousel-inner .item img[src$=".svg"] { 41 | width: 100%; 42 | } 43 | 44 | /* Hide/rearrange for smaller screens */ 45 | @media screen and (max-width: 767px) { 46 | /* Hide captions */ 47 | .carousel-caption { 48 | display: none; 49 | } 50 | } 51 | 52 | /*IS4 CSS*/ 53 | .validation-summary-valid{ 54 | display:none; 55 | } 56 | 57 | .logged-out iframe { 58 | display: none; 59 | width: 0; 60 | height: 0; 61 | } 62 | .page-consent .client-logo { 63 | float: left; 64 | } 65 | .page-consent .client-logo img { 66 | width: 80px; 67 | height: 80px; 68 | } 69 | .page-consent .consent-buttons { 70 | margin-top: 25px; 71 | } 72 | .page-consent .consent-form .consent-scopecheck { 73 | display: inline-block; 74 | margin-right: 5px; 75 | } 76 | .page-consent .consent-form .consent-description { 77 | margin-left: 25px; 78 | } 79 | .page-consent .consent-form .consent-description label { 80 | font-weight: normal; 81 | } 82 | .page-consent .consent-form .consent-remember { 83 | padding-left: 16px; 84 | } -------------------------------------------------------------------------------- /IdentityApp/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}input,select,textarea{max-width:280px}.carousel-caption p{font-size:20px;line-height:1.4}.btn-bracketed::before{display:inline-block;content:"[";padding-right:.5em}.btn-bracketed::after{display:inline-block;content:"]";padding-left:.5em}.carousel-inner .item img[src$=".svg"]{width:100%}@media screen and (max-width:767px){.carousel-caption{display:none}}.validation-summary-valid{display:none}.logged-out iframe{display:none;width:0;height:0}.page-consent .client-logo{float:left}.page-consent .client-logo img{width:80px;height:80px}.page-consent .consent-buttons{margin-top:25px}.page-consent .consent-form .consent-scopecheck{display:inline-block;margin-right:5px}.page-consent .consent-form .consent-description{margin-left:25px}.page-consent .consent-form .consent-description label{font-weight:normal}.page-consent .consent-form .consent-remember{padding-left:16px} -------------------------------------------------------------------------------- /IdentityApp/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/favicon.ico -------------------------------------------------------------------------------- /IdentityApp/wwwroot/icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/icon.jpg -------------------------------------------------------------------------------- /IdentityApp/wwwroot/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/icon.png -------------------------------------------------------------------------------- /IdentityApp/wwwroot/js/signout-redirect.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", function () { 2 | var a = document.querySelector("a.PostLogoutRedirectUri"); 3 | if (a) { 4 | window.location = a.href; 5 | } 6 | }); 7 | -------------------------------------------------------------------------------- /IdentityApp/wwwroot/js/site.js: -------------------------------------------------------------------------------- 1 | // Write your Javascript code. 2 | -------------------------------------------------------------------------------- /IdentityApp/wwwroot/js/site.min.js: -------------------------------------------------------------------------------- 1 | // Write your Javascript code. -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap", 3 | "description": "The most popular front-end framework for developing responsive, mobile first projects on the web.", 4 | "keywords": [ 5 | "css", 6 | "js", 7 | "less", 8 | "mobile-first", 9 | "responsive", 10 | "front-end", 11 | "framework", 12 | "web" 13 | ], 14 | "homepage": "http://getbootstrap.com", 15 | "license": "MIT", 16 | "moduleType": "globals", 17 | "main": [ 18 | "less/bootstrap.less", 19 | "dist/js/bootstrap.js" 20 | ], 21 | "ignore": [ 22 | "/.*", 23 | "_config.yml", 24 | "CNAME", 25 | "composer.json", 26 | "CONTRIBUTING.md", 27 | "docs", 28 | "js/tests", 29 | "test-infra" 30 | ], 31 | "dependencies": { 32 | "jquery": "1.9.1 - 2" 33 | }, 34 | "version": "3.3.6", 35 | "_release": "3.3.6", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.3.6", 39 | "commit": "81df608a40bf0629a1dc08e584849bb1e43e0b7a" 40 | }, 41 | "_source": "git://github.com/twbs/bootstrap.git", 42 | "_target": "3.3.6", 43 | "_originalSource": "bootstrap" 44 | } -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2011-2015 Twitter, Inc 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elanderson/Angular-Core-IdentityServer/221ec59010f98b078fd886a294b9b44cb5c3c077/IdentityApp/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/jquery-validation-unobtrusive/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation-unobtrusive", 3 | "version": "3.2.6", 4 | "homepage": "https://github.com/aspnet/jquery-validation-unobtrusive", 5 | "description": "Add-on to jQuery Validation to enable unobtrusive validation options in data-* attributes.", 6 | "main": [ 7 | "jquery.validate.unobtrusive.js" 8 | ], 9 | "ignore": [ 10 | "**/.*", 11 | "*.json", 12 | "*.md", 13 | "*.txt", 14 | "gulpfile.js" 15 | ], 16 | "keywords": [ 17 | "jquery", 18 | "asp.net", 19 | "mvc", 20 | "validation", 21 | "unobtrusive" 22 | ], 23 | "authors": [ 24 | "Microsoft" 25 | ], 26 | "license": "http://www.microsoft.com/web/webpi/eula/net_library_eula_enu.htm", 27 | "repository": { 28 | "type": "git", 29 | "url": "git://github.com/aspnet/jquery-validation-unobtrusive.git" 30 | }, 31 | "dependencies": { 32 | "jquery-validation": ">=1.8", 33 | "jquery": ">=1.8" 34 | }, 35 | "_release": "3.2.6", 36 | "_resolution": { 37 | "type": "version", 38 | "tag": "v3.2.6", 39 | "commit": "13386cd1b5947d8a5d23a12b531ce3960be1eba7" 40 | }, 41 | "_source": "git://github.com/aspnet/jquery-validation-unobtrusive.git", 42 | "_target": "3.2.6", 43 | "_originalSource": "jquery-validation-unobtrusive" 44 | } -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/jquery-validation/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-validation", 3 | "homepage": "http://jqueryvalidation.org/", 4 | "repository": { 5 | "type": "git", 6 | "url": "git://github.com/jzaefferer/jquery-validation.git" 7 | }, 8 | "authors": [ 9 | "Jörn Zaefferer " 10 | ], 11 | "description": "Form validation made easy", 12 | "main": "dist/jquery.validate.js", 13 | "keywords": [ 14 | "forms", 15 | "validation", 16 | "validate" 17 | ], 18 | "license": "MIT", 19 | "ignore": [ 20 | "**/.*", 21 | "node_modules", 22 | "bower_components", 23 | "test", 24 | "demo", 25 | "lib" 26 | ], 27 | "dependencies": { 28 | "jquery": ">= 1.7.2" 29 | }, 30 | "version": "1.14.0", 31 | "_release": "1.14.0", 32 | "_resolution": { 33 | "type": "version", 34 | "tag": "1.14.0", 35 | "commit": "c1343fb9823392aa9acbe1c3ffd337b8c92fed48" 36 | }, 37 | "_source": "git://github.com/jzaefferer/jquery-validation.git", 38 | "_target": ">=1.8", 39 | "_originalSource": "jquery-validation" 40 | } -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/jquery-validation/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright Jörn Zaefferer 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/jquery/.bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery", 3 | "main": "dist/jquery.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "package.json" 7 | ], 8 | "keywords": [ 9 | "jquery", 10 | "javascript", 11 | "browser", 12 | "library" 13 | ], 14 | "homepage": "https://github.com/jquery/jquery-dist", 15 | "version": "2.2.0", 16 | "_release": "2.2.0", 17 | "_resolution": { 18 | "type": "version", 19 | "tag": "2.2.0", 20 | "commit": "6fc01e29bdad0964f62ef56d01297039cdcadbe5" 21 | }, 22 | "_source": "git://github.com/jquery/jquery-dist.git", 23 | "_target": "2.2.0", 24 | "_originalSource": "jquery" 25 | } -------------------------------------------------------------------------------- /IdentityApp/wwwroot/lib/jquery/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | All files located in the node_modules and external directories are 34 | externally maintained libraries used by this software which have their 35 | own licenses; we recommend you read them, as their terms may differ from 36 | the terms above. 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Eric Anderson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angular-Core-IdentityServer 2 | Exploring Angular (4+) with ASP.NET Core, Entity Framework Core and IdentityServer4. The following are blog posts documenting the exploration. 3 | 4 | ## Initial Exploration 5 | 6 | 1. [Identity Server: Introduction](https://elanderson.net/2017/05/identity-server-introduction/) 7 | 2. [Identity Server: Sample Exploration and Initial Project Setup](https://elanderson.net/2017/06/identity-server-sample-exploration-and-initial-project-setup/) 8 | 3. [Identity Server: Interactive Login using MVC](https://elanderson.net/2017/07/identity-server-interactive-login-using-mvc/) 9 | 4. [Identity Server: From Implicit to Hybrid Flow](https://elanderson.net/2017/07/identity-server-from-implicit-to-hybrid-flow/) 10 | 5. [Identity Server: Using ASP.NET Core Identity](https://elanderson.net/2017/07/identity-server-using-asp-net-core-identity/) 11 | 6. [Identity Server: Using Entity Framework Core for Configuration Data](https://elanderson.net/2017/07/identity-server-using-entity-framework-core-for-configuration-data/) 12 | 7. [Identity Server: Usage from Angular](https://elanderson.net/2017/07/identity-server-usage-from-angular/) 13 | 8. [Identity Server: Calling Secured API from Angular](https://elanderson.net/2017/08/identity-server-calling-secured-api-from-angular/) 14 | 15 | ## Other Related Posts 16 | 1. [Identity Server: Redirect When Route Requires Logged in User](https://elanderson.net/2017/08/identity-server-redirect-when-route-requires-logged-in-user/) 17 | 2. [Identity Server: Changing Angular OpenID Connect Clients](https://elanderson.net/2017/09/identity-server-changing-angular-openid-connect-clients/) 18 | 3. [Identity Server: External Authentication using Twitter](https://elanderson.net/2017/09/identity-server-external-authentication-using-twitter/) 19 | 4. [Identity Server: API Migration to ASP.NET Core 2](https://elanderson.net/2017/09/identity-server-api-migration-to-asp-net-core-2/) 20 | 5. [Identity Server: Migration to ASP.NET Core 2](https://elanderson.net/2017/10/identity-server-migration-to-asp-net-core-2/) 21 | 6. [Identity Server: Deploy to Azure](https://elanderson.net/2017/11/identity-server-deploy-to-azure/) 22 | 7. [Identity Server: Upgrade Client to Angular 5](https://elanderson.net/2017/12/identity-server-upgrade-client-to-angular-5/) 23 | 8. [Identity Server: Migration to version 2.1 and Angular HTTP Changes](https://elanderson.net/2018/02/identity-server-migration-to-version-2-1-and-angular-http-changes/) 24 | --------------------------------------------------------------------------------