Introduction
Identity Server4 is an open-source authentication provider with OpenID connect and OAuth2.0 framework for ASP.NET Core. It acts as a centralized authentication provider or security token server (STS). It will be ideal to go through layers when you have multiple API/microservices applications and you should have single security token server to handle the authentication so that you really don’t have to define the Authentication in each and every application.
Identity server4 is a simple and straightforward STS. The user uses the clients (ASP.NET MVC or angular or react application and so on) to access the data, these users are authenticated by Identity Server to use the client. After successful authentication, the Identity server will send a token to client. Then client should use this token to access the data from the APIs.
Identity server4 provides the flexibility to use external storage like relational database, NoSQL, or in-memory data storage. NCache, being a distributed and scalable in-memory key-value data store is a great fit for IdentityServer4. In this article, you will learn how to use NCache as external in-memory storage for identityServer4. The main advantage of using external in-memory storage is to improve the application performance
Advantages of using Identity Server4
- Secure your resources
- Authenticate users either using a local account store or an external provider
- Validate tokens
What is NCache?
NCache is an open source distributed In-memory datastore, also called as distributed cache, in the .NET space and In-memory data gird in the java space. Since it is a distributed In-memory it’s extremely fast and scalable. It’s a native .NET solution and it’s easy to integrate to our application with .NET Stack. We will get a lot of benefits from NCache with our application, while dealing with processing the large amount of transaction during peak times. Basically, data storage and database cannot cope with such high transactions loads and becomes a bottleneck. To overcome this performance issue, we can go with Distributed cache with NCache which can store all transient or temporary data in it. Unlike database, NCache distributed cache allows you to build a caching tier, of two or more servers, pools the memory and CPU of all the cache server into one logical capacity. NCache will also provide a provision to add more servers as your transaction loads grow. So, NCache can scale linearly.
Using NCache as IdentityServer4
NCache can be used with IdentityServer in the following ways,
- NCache as IdentityServer4 Store
- NCache as IdentityServer4 Cache
Note: Both cache and store roles of NCache with IdentityServer4 can also be a mix and match using the implementation from IIdentityServerBuilder NCache extension for ASP.NET Core.
For NCache Installation, I highly recommend you go through a step-by-step tutorial on how to download and install a NCache on your windows machine here.
1. NCache as an In-Memory IdentityServer4 Store
Configuration and operational data, such as client information, Identity resources, API resources, device flow codes, etc., can be stored using NCache as an In-Memory IdentityServer4 Store, making this a much better server alternative for storing data.
With its In-Memory caching, NCache as a store speeds up operational flow and eliminates database hits. Essentially, IdentityServer4 handles all the required authentication at each network hop in your application, and NCache works well to store the operational and configuration data for quicker access.
The below figure will give you a complete understanding of NCache as an In-Memory IdentityServer4 Store.
NCache as IdentityServer4 Storage
From the above figure its obvious the NCache an in-memory distributed cache can acts as both a Configuration and Operational storage or Configuration storage as a SQL Server or some other data storage and the Operational storage as an NCache Server and vice versa.
What is Configuration storage?
It's a storage where the static data are stored, which doesn’t change frequently. In our case the data like client and identity resource information which remains unchanged for a long time will be stored.
What is an Operational storage?
It's a storage where the frequently modified data will be stored. Basically, it holds the sensitive data with up-to-date information integrated from operational sources. In our case it can be persisted grants and device flow codes.
Configure NCache for Configuration and Operational data store
For a demo, I have used my existing ASP.NET Core IdentityServer4 application, you can download it from GiHub.
- Download and install “Alachisoft.NCache.IdentityServer4” package from NuGet Package Manager
- Create a new Startup file “StartupNCache.cs” and add the following code.
public void ConfigureServices(IServiceCollection services) {
services.AddControllersWithViews();
var builder = services.AddIdentityServer().AddTestUsers(TestUsers.Users)
/// Add NCache as a configuration store
.AddNCacheConfigurationStore(options => {
options.CacheId = _configuration["NCacheConfiguration:CacheId"];
var serverList = _configuration["Servers"].Split(',').Select(x => x.Trim()).ToList().Select(y => new NCacheServerInfo(y, 9800)).ToList();
options.ConnectionOptions = new NCacheConnectionOptions {
ServerList = serverList,
EnableClientLogs = true,
LogLevel = NCacheLogLevel.Debug
};
})
/// Add NCache as an operational store
.AddNCachePersistedGrantStore(options => {
options.CacheId = _configuration["NCacheConfiguration:CacheId"];
var serverList = _configuration["NCacheConfiguration:Servers"].Split(',').Select(x => x.Trim()).ToList().Select(y => new NCacheServerInfo(y, 9800)).ToList();
options.ConnectionOptions = new NCacheConnectionOptions {
ServerList = serverList,
EnableClientLogs = true,
LogLevel = NCacheLogLevel.Debug
};
}).AddNCacheDeviceCodeStore(options => {
options.CacheId = _configuration["NCacheConfiguration:CacheId"];
var serverList = _configuration["NCacheConfiguration:Servers"].Split(',').Select(x => x.Trim()).ToList().Select(y => new NCacheServerInfo(y, 9800)).ToList();
options.ConnectionOptions = new NCacheConnectionOptions {
ServerList = serverList,
EnableClientLogs = true,
LogLevel = NCacheLogLevel.Debug
};
})
}
Let’s configure the NCache connection. In appsettings.json file, update the value of the CacheId key to the name of the cluster cache you are using. In case if you are using multiple servers for making up the NCache cluster, separate the NCache Servers key values(IP addresses) with comma.
"NCacheConfiguration": {
"CacheId": "demoCache",
"Servers": "[your server adddress]"
},
Replace [your server address] with your NCache server IP address used for Clustred Caches in my case it is 192.168.1.2.
Define the new startup file in program.cs file
webBuilder.UseStartup<StartupNCache>();
Run the application, let's test the token generation from postman.
From the above figure you can observe, the ASP.NET Core application with NCache as IdentityServer4 running under port 5000 and the token has been successfully generated from Postman tool. Now open NCache web manager to check the statistics.
NCache Cluster Cache Statistics
From the above statistics, the clients parameter gives you the no of connection established count, In my case, I have connected only one application to the NCache clustered cache, so the Clients count is 1.
The count parameter gives you the number of key value pair cached.
2. NCache as an In-Memory IdentityServer4 Cache Implementation
To increase an application performance further, NCache can be used as an In-Memory IdentityServer4 Cache. This approach will get rid of the process of getting a data from disk again and again.
The below figure will give you a complete understanding of NCache as an In-Memory IdentityServer4 Cache.
NCache as IdentityServer4 Cache
From the above figure, it’s quite obvious we can use NCache between our data store and application by caching the Configuration and/or Operational data.
Create a new file StartupEFCore and add the below code,
public void ConfigureServices(IServiceCollection services) {
...
var builder = services.AddIdentityServer().AddTestUsers(TestUsers.Users)
/// Add NCache as a configuration store
.AddNCacheCaching(options => {
options.CacheId = _configuration["NCacheConfiguration:CacheId"];
var serverList = _configuration["Servers"].Split(',').Select(x => x.Trim()).ToList().Select(y => new NCacheServerInfo(y, 9800)).ToList();
options.ConnectionOptions = new NCacheConnectionOptions {
ServerList = serverList
};
options.DurationOfBreakInSeconds = 120;
})
/// Add NCache as a persisted operational grant store
.AddClientStoreCache < ClientStore > ().AddResourceStoreCache < ResourceStore > ().AddNCacheCorsPolicyCache < CorsPolicyService > ().AddNCachePersistedGrantStoreCache < PersistedGrantStore > (options => {
options.CacheId = _configuration["NCacheConfiguration:CacheId"];
var serverList = _configuration["NCacheConfiguration:Servers"].Split(',').Select(x => x.Trim()).ToList().Select(y => new NCacheServerInfo(y, 9800)).ToList();
options.ConnectionOptions = new NCacheConnectionOptions {
ServerList = serverList
};
options.DurationOfBreakInSeconds = 120;
})
/// NCache as an IProfileService default implementation
.AddNCacheProfileServiceCache < TestUserProfileService > (options => {
options.Expiration = TimeSpan.FromMinutes(10);
options.KeyPrefix = "NCache-";
options.KeySelector = (context) => context.Subject.Claims.First(_ => _.Type == "sub").Value;
options.ShouldCache = (context) => true;
});
}
Since we are using EF Core, add following packages from NuGet Package manager
"IdentityServer4.EntityFramework"
“Microsoft.EntityFrameworkCore.SqlServer”
“Microsoft.EntityFrameworkCore.Tools”
In Program.cs, set the startup file as StartupEFCore.
The migration folders are already available in this existing project.
Use update-database command from Package Manager Console in Visual Studio to create/update the database tables based on the migration information. Make sure you have given a database connection string and NCache server configuration settings(NCache - CacheId and NCache Server IP Address) in your appsettings.json file .
Run the application, the client information are stored in the database. Since we have NCache with Configurational and Operational storage the data will be cached by NCache Clustered cache, so that we can skip the database transaction to improve our application performance.
Database tables
Get the token using Postman
Trace of the database transaction given below, while getting a token using Postman.
First time it will hit a database to generate a new token.
Check the Cache count in NCache web Manager
NCache Cluster Cache Statistics
Previously the count is 6, and now the count is 9 and the cache size also increased, which means the token has been cached to NCache Clustered cache. Next time when you try to get a token, there won't be any database transaction
Once again get the token from Postman, now the token and other details are from NCache server. So no database transaction had happened when you try to get the token for second time. This approach will help us to improve the application performance by reducing the database trips.
Reference
NCache as IdentityServer4 Cache and Data Store | NCache Docs (alachisoft.com)
Summary
Implementing the OpenId Connect using IdentitServer4 will secure our application by authenticating the user, on top of it by integrating the NCache as an external storage will improve your application performance and also, it’s provided you a lot of features by acting as IdentityServer Cache and store.