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 |
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 |
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 |
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 |
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 |
14 | Disabling 2FA does not change the keys used in authenticator apps. If you wish to change the key
15 | used in an authenticator app you should reset your
16 | authenticator keys.
17 |
To use an authenticator app go through the following steps:
10 |
11 |
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 |
22 |
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 |
28 |
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 |
9 |
10 | If you reset your authenticator key your authenticator app will not work until you reconfigure it.
11 |
12 |
13 | This process disables 2FA until you verify your authenticator app and will also reset your 2FA recovery codes.
14 | If you do not complete your authenticator app configuration you may lose access to your account.
15 |