SECRET OF CSS

Using NCache as IdentityServer4 Cache and Store


Identity Server4 is an authentication provider. It is an open-source OpenID Connect and OAuth2.0 framework for ASP.NET Core. The main objective of OpenID Connect is to centralize the authentication process. This centralized authentication provider or Security token server (STS) is a great solution for the application working with more than 2 APIS/microservices where you don’t want to use a different authentication provider for each service. From IdentityServer4, you will get centralized access control to secure every API by the central Identity Server. Mainly the STS is responsible for issuing tokens and validating claims.  

Identity Server4 provides the flexibility to use external storage like a relational database, NoSQL, a file system, or in-memory data storage. NCache, being a distributed and scalable in-memory key-value data store, is a great fit for IdentityServer4. This article will teach you how to use NCache as external in-memory storage for identityServer4. You may get a question here, why is external in-memory storage required? Using external in-memory storage like NCache will improve the application performance and will give you a faster result.

Advantages of Using Identity Server4  

  1. Secure your resources. 
  2. Authenticate users either using a local account store or an external provider.
  3. Validate tokens  

IdentityServer With NCache

 NCache can be used with IdentityServer in the following ways.

NCache as IdentityServer4 Store

NCache acts as a caching layer on top of the IdentityServer 4 persistence configuration and operational stores to speed up the operation through in-memory caching and also reduce the frequent database hits.

NCache as IdentityServer4 Cache

NCache can be used as a configuration and persistent grant store, which increases performance by removing the bottleneck to get data from a disk. The in-memory content of the cache can then be periodically persisted to disk, reducing the average time taken to get the data.

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.  

What Is a Configuration Store?

A store where the static data is stored which doesn’t change frequently.

What Is an Operational Store?

A store where the operational data is kept on which operations are performed, and the changes are applied more frequently. 

For NCache Installation, I highly recommend you go through a step-by-step tutorial on downloading and installing an NCache on your windows machine here.

NCache as an In-Memory IdentityServer4 Store

NCache, as an IdentityServer4 Store, stores information about the clients, Identity resources and APIs, etc. You have an option to choose NCache as one store or both of them. 

The below figure will give you a complete understanding of NCache as an In-Memory IdentityServer4 Store.

 NCache as IdentityServer4 Store.

NCache as IdentityServer4 Store

                            

Option 1: NCache store acts as both a configuration and operational store. 

Option 2: Configuration Storage as a SQL Server or some other storage and the Operational storage as an NCache Server.  

Configure NCache as IdentityServer4 Store

For a demo, I have used my existing ASP.NET Core IdentityServer4 application; you can download it from GitHub

1. Download and install the “Alachisoft.NCache.IdentityServer4” package from NuGet Package Manager. 

2. 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
                };
            })
}

In the appsettings.json file, modify the value of the CacheId key to the name of the cluster cache you are using. For multiple Servers keys, use a comma-separated list of one or more IP addresses belonging to the NCache servers.

  "NCacheConfiguration": {
    "CacheId": "demoCache",
    "Servers": "10.0.0.4"
  },

Define the new startup file in the program.cs file. 

webBuilder.UseStartup<StartupNCache>();

Run the application and parallelly check the Clustered NCache stats; you will find the client count as 1, which means your application connects with NCache.

Clustered NCache stats.

NCache Cluster Cache Stats

                                                               NCache Cluster Cache Stats.

NCache as an In-Memory IdentityServer4 Cache Implementation

NCache’s core functionality is to cache data persisting in your data source for faster access and better performance. While you can use NCache as your data store, you can also use it between your data store and the application by caching the configuration and/or the operational data in NCache.

The below figure will give you a complete understanding of NCache as an In-Memory IdentityServer4 Cache. 

NCache as IdentityServer4 Cache.

                                                            NCache as IdentityServer4 Cache.

For a demo, I used the GitHub repository from NCache.

Install the following NuGet package to your application:

             “Alachisoft.NCache.IdentityServer4″”

Create a new file, StartupEFCore, and add the following code,

Download and install the “IdentityServer4.NCache.Options” package from the NuGet package manager.

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["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;
        });
    
}

In the appsettings.json file, modify the value of the CacheId key to the name of the cluster cache you are using. For multiple Servers keys, use a comma-separated list of one or more IP addresses belonging to the NCache servers.

{
      "NCacheConfiguration": {
    "CacheId": "demoCache",
    "Servers": "10.0.0.4"
  },

    "ConnectionStrings" : {
        "db" : "server=;database=IdentityServer4.EntityFramework;UserId=userid;Password=password;"
    }
}

Run the application and parallelly check the Clustered NCache stats; you will find the client count as 1, which means your application connects with NCache. 

 Clustered NCache stats.

Implementing the OpenId Connect using IdentitServer4 will secure our application by authenticating the user; on top of it, integrating the NCache as external storage will improve your application performance and also, it’s provided you with a lot of features by acting as IdentityServer Cache and store. 



News Credit

%d bloggers like this: