IdentityServer4.Admin
https://github.com/skoruba/IdentityServer4.Admin
Angular with Asp.Net Core and IdentityServer4 (edit)
https://github.com/mmacneil/AngularASPNETCoreOAuth
Identity and Access Control
Identity as the name might suggest, means some set of attributes that a computer system can use to represent a person, organization, application or device. Access control, on the other hand, refers to a security technique used to regulate who or what can access and use resources (data and operations) in a computing environment.
Authentication and Authorization
Authentication means the process used to determine whether a user is who they claim to be. Once authenticated, authorization determines which resources a given user should be able to access, and what they're allowed to do with those resources.
OpenID Connect and OAuth
OpenID Connect (OIDC) is a simple identity and authentication protocol layer built on top of the OAuth protocol that allows applications (typically referred to as clients) to verify the identity of end-users. OAuth is an open standard for authorization that provides secure, delegated access, meaning that an application (or client) can take actions or access resources on a resource server on behalf of a user, without the user ever sharing their credentials with the application - the key being delegated access.
Here's a diagram showing how these concepts and protocols fit together in a basic authentication and authorization scenario.
OIDC/OAuth flow.
To summarize this workflow:
-
The user (resource owner) initiates an authentication request with the authorization server.
-
If the credentials are valid and everything checks out the authorization server obtains end-user consent and grants the client application an access token.
-
The access token is attached to subsequent requests made to the protected resource server.
-
The authorization server validates the access token; if successful the request for protected resources is granted, and a response sent back to the client application.
Ok, we've covered off some theory behind identity, access control, OpenID Connect, and OAuth. Now we'll look at implementing a similar workflow using Angular, ASP.NET Core and IdentityServer4.
Development Environment
As of March 31, 2019, the demo solution builds and runs successfully with the following tools and SDKs:
- Visual Studio 2019 Community
- Visual Studio Code 1.32.3
- .NET Core SDK 2.2.104
- Angular 7.2.9
- IdentityServer4 2.4.0
- SQL Server Express 2016 LocalDB
Architecture
Our solution architecture has three main components:
- SPA client application - Angular
- Authorization/Identity server - ASP.NET Core MVC and IdentityServer4
- Resource server - ASP.NET Core Web API
Now, we'll step through the process to build out and integrate these components to create the demo solution.
AuthServer
The AuthServer is our OpenID Connect and OAuth provider so it's a great place to start as it is essentially the hub of our solution.
I created a new project using the out of the box ASP.NET Core MVC template. The next step is to bootstrap it with the required IdentityServer packages. I nugetted the main IdentityServer4 package along with IdentityServer4.AspNetIdentity. The second package provides integration between IdentityServer and ASP.NET Core's Identity system which we'll explore shortly. You can use your preferred NuGet method; I use the package manager console in Visual Studio.
PM> Install-Package IdentityServer4
PM> Install-Package IdentityServer4.AspNetIdentity
Configuring IdentityServer
With the packages installed, we're ready to turn on IdentityServer in our project. IdentityServer uses the standard pattern to configure and add its services to your ASP.NET Core application via the middleware configuration in Startup.cs. In ConfigureServices() the required services are configured and added to the DI system. In Configure() the middleware is added to the HTTP pipeline.
Here are the relevant bits from the Startup class.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddDbContext<AppIdentityDbContext> (options => options.UseSqlServer(Configuration.GetConnectionString("Default")));
services.AddIdentity<AppUser, IdentityRole>()
.AddEntityFrameworkStores<AppIdentityDbContext>()
.AddDefaultTokenProviders();
services.AddIdentityServer().AddDeveloperSigningCredential()
// this adds the operational data from DB (codes, tokens, consents)
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder => builder.UseSqlServer(Configuration.GetConnectionString("Default"));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30; // interval in seconds
})
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<AppUser>();
...
}
Our demo uses the in-memory style for clients and resources, and those are sourced from Config.cs. The framework thoughtfully provides a couple of helpers and in-memory stores, so we don’t have to worry about persistence right from the start for that stuff.
Notice also, the necessary AddDbContext<AppIdentityDbContext> and AddIdentity<AppUser, IdentityRole> calls are done to configure ASP.NET Identity - we'll touch on this next.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
app.UseIdentityServer();
...
}
Finally, we add IdentityServer to our request processing pipeline in Configure(), and that's it for now!
User Data and ASP.NET Core Identity
We need somewhere to store our application's user data - things like their credentials, profile information, etc. For this, we can leverage ASP.NET Core's Identity system and use the default data access approach with Sql Server and Entity Framework Core handling persistence. A further benefit of this setup is that the Identity system plugs nicely into IdentityServer to provide user profile and claims data which we'll see shortly.