Skip to content

AuthServer

  • Configure OpenIddict library

Add GetSigningCertificate and GetEncryptionCertificate certificate method for handling certificates.

using GridLab.Abp.ZeroTrust;

private X509Certificate2 GetSigningCertificate(ServiceConfigurationContext context, IConfiguration configuration)
{
    var certificateFactory = context.Services.GetCertificateFactory();

    return certificateFactory.CreateFromPkcs12File(
        configuration["App:Certificates:Signing:Path"],
        configuration["App:Certificates:Signing:CertPassphrase"]
    );
}
using GridLab.Abp.ZeroTrust;

private X509Certificate2 GetEncryptionCertificate(ServiceConfigurationContext context, IConfiguration configuration)
{
    var certificateFactory = context.Services.GetCertificateFactory();

    return certificateFactory.CreateFromPkcs12File(
        configuration["App:Certificates:Encryption:Path"],
        configuration["App:Certificates:Encryption:CertPassphrase"]
    );
}

Add GetIssuer and GetAccessTokenLifetime specific library options methods.

private string GetIssuer(IConfiguration configuration)
{
    // Solves bearer was not authenticated. Failure message: IDX10205: Issuer validation failed.
    var issuer = configuration["App:Issuer"]?.Trim();
    var selfUrl = configuration["App:SelfUrl"]?.Trim();

    if (!string.IsNullOrEmpty(issuer))
        return issuer;

    if (!string.IsNullOrEmpty(selfUrl))
        return selfUrl;

    throw new InvalidOperationException("Neither App:Issuer nor App:SelfUrl is provided in configuration.");
}

private TimeSpan GetAccessTokenLifetime(IConfiguration configuration)
{
    var accessTokenLifetimeString = configuration["App:AccessTokenLifetime"]?.Trim();

    var defaultAccessTokenLifetime = TimeSpan.FromHours(1);  // Define a default fallback value (1 hour)

    if (TimeSpan.TryParse(accessTokenLifetimeString, out var accessTokenLifetime))
        return accessTokenLifetime;

    return defaultAccessTokenLifetime;
}
  • Add Hangfire support.

Install GridLab.Abp.Hangfire module.

<ItemGroup>
  <PackageReference Include="GridLab.Abp.Hangfire" Version="X.Y.Z" />
</ItemGroup>

Replace version number with latest available.

Add the AbpHangfireModule to the dependency list of your module:

[DependsOn(
    //...other dependencies
    typeof(AbpGridLabHangfireModule)
)]
public class GMSSAuthServerModule : AbpModule
{
}

Configure Hangfire module;

private void ConfigureHangfire(ServiceConfigurationContext context, IConfiguration configuration)
{
    string serverName = configuration["Hangfire:ServerName"] ?? "gmss-auth-server";
    string schemaName = configuration["Hangfire:SchemaName"] ?? string.Empty;

    string? connectionString = configuration.GetConnectionString(GMSSDbProperties.ConnectionStringHangfireName);

    if (connectionString.IsNullOrEmpty())
        throw new ArgumentNullException(paramName: GMSSDbProperties.ConnectionStringHangfireName);

    var serverStorageOptions = new EFCoreStorageOptions
    {
        CountersAggregationInterval = new TimeSpan(0, 5, 0),
        DistributedLockTimeout = new TimeSpan(0, 10, 0),
        JobExpirationCheckInterval = new TimeSpan(0, 30, 0),
        QueuePollInterval = new TimeSpan(0, 0, 15),
        Schema = schemaName,
        SlidingInvisibilityTimeout = new TimeSpan(0, 5, 0),
    };

    var options = new DbContextOptionsBuilder<GMSSHangfireDbContext>()
        .UseSqlServer(connectionString)
        .Options;

    GlobalConfiguration.Configuration.UseEFCoreStorage(
         () => new GMSSHangfireDbContext(options, schemaName),
         serverStorageOptions
    );

    Configure<AbpHangfireOptions>(options =>
    {
        options.Storage = EFCoreStorage.Current;
        options.ServerOptions = new BackgroundJobServerOptions() { ServerName = serverName };
    });
}

Add a new section for hangfire to application configuration settings.

"Hangfire": {
  "ServerName": "gmss-auth-server"
},

Make sure you have updated your connection strings defined under ConnectionString at appsettings.json file.

"ConnectionStrings": {
  ...
  "Hangfire": "Server=(localdb)\\MSSQLLocalDB;Database=gmss-hangfire;Trusted_Connection=True;TrustServerCertificate=true"
}
  • Configure caching.

Replace Volo.Abp.Caching.StackExchangeRedis with GridLab.Abp.Caching.StackExchangeValkey module.

Remove:

<ItemGroup>
  <PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" Version="X.Y.Z" />
</ItemGroup>

Add:

<ItemGroup>
  <PackageReference Include="GridLab.Abp.Caching.StackExchangeValkey" Version="X.Y.Z" />
</ItemGroup>

Replace package at GMSSAuthServerModule.cs

[DependsOn(
    typeof(GMSSEntityFrameworkCoreModule)
    //...other dependencies
    ~~typeof(AbpStackExchangeRedisModule),~~
    typeof(AbpGridLabStackExchangeValkeyModule),
    //...other dependencies
)]
public class GMSSAuthServerModule : AbpModule
{
}

Add ConfigureCache, ConfigureDataProtection and ConfigureDistributedLocking methods for handling cache connections.

private void ConfigureCache(IConfiguration configuration)
{
    Configure<AbpDistributedCacheOptions>(options =>
    {
        options.KeyPrefix = "GMSS:";
    });
}

Use AbpValkeyConfigurationHelper.CreateConfigurationOptions helper method to create connection.

private void ConfigureDataProtection(
    ServiceConfigurationContext context,
    IConfiguration configuration,
    IWebHostEnvironment hostingEnvironment)
{
    if (AbpStudioAnalyzeHelper.IsInAnalyzeMode)
    {
        return;
    }

    var dataProtectionBuilder = context.Services.AddDataProtection().SetApplicationName("GMSS");

    if (!hostingEnvironment.IsDevelopment())
    {
        var certificateProvider = context.Services.GetCertificateProvider();
        var certificateValidator = context.Services.GetCertificateValidator();

        var options = configuration
            .GetSection(AbpGridLabValkeyOptions.ServiceName)
            .Get<AbpGridLabValkeyOptions>() ?? new AbpGridLabValkeyOptions();

        var configurationOptions = AbpValkeyConfigurationHelper.CreateConfigurationOptions(
            serviceOptions: options,
            certificateProvider: certificateProvider,
            certificateValidator: certificateValidator
        );

        var redis = ConnectionMultiplexer.Connect(configurationOptions);
        dataProtectionBuilder.PersistKeysToStackExchangeRedis(redis, "GMSS-Protection-Keys");
    }
}
private void ConfigureDistributedLocking(ServiceConfigurationContext context, IConfiguration configuration)
{
    if (AbpStudioAnalyzeHelper.IsInAnalyzeMode)
    {
        return;
    }

    context.Services.AddSingleton<IDistributedLockProvider>(sp =>
    {
        var certificateProvider = context.Services.GetCertificateProvider();
        var certificateValidator = context.Services.GetCertificateValidator();

        var options = configuration
            .GetSection(AbpGridLabValkeyOptions.ServiceName)
            .Get<AbpGridLabValkeyOptions>() ?? new AbpGridLabValkeyOptions();

        var configurationOptions = AbpValkeyConfigurationHelper.CreateConfigurationOptions(
            serviceOptions: options,
            certificateProvider: certificateProvider,
            certificateValidator: certificateValidator
        );

        var connection = ConnectionMultiplexer.Connect(configurationOptions);
        return new RedisDistributedSynchronizationProvider(connection.GetDatabase());
    });
}

Add a new section for caching to application configuration settings.

"Valkey": {
  "Enabled": true,
  "Configuration": {
    "Configuration": "127.0.0.1"
  },
  "Ssl": {
    "Enabled": false
  },
  "Connection": {
    "ConnectTimeout": 30,
    "ConnectRetry": 3
  }
},
  • Activate clock at GMSSAuthServerModule.cs, default Kind is Unspecified that actually make the Clock as it doesn't exists at all.
private void ConfigureClock()
{
    Configure<AbpClockOptions>(options =>
    {
        options.Kind = DateTimeKind.Utc;
    });
}
  • Install GridLab.Abp.Security.Providers.DockerSecrets module.
<ItemGroup>
  <PackageReference Include="GridLab.Abp.Security.Providers.DockerSecrets" Version="X.Y.Z" />
</ItemGroup>

Replace version number with latest available.

Extend dependency list at GMSSAuthServerModule.cs

[DependsOn(
    typeof(GMSSEntityFrameworkCoreModule)
    //
    typeof(AbpGridLabSecurityProvidersDockerSecretsModule),
    //...other dependencies
)]
public class GMSSAuthServerModule : AbpModule
{
}

.NET Core configuration provider extensions allows reading docker secrets files and pull them into the .net core configuration.

builder.Host
    .UseAutofac()
    ....
    .UseSerilog((context, services, loggerConfiguration) =>
    {
        loggerConfiguration
#if DEBUG
        .MinimumLevel.Debug()
        .MinimumLevel.Override("DockerSecrets", LogEventLevel.Debug)
#else
        .MinimumLevel.Information()
        .MinimumLevel.Override("DockerSecrets", LogEventLevel.Information)
#endif
        .MinimumLevel.Override("Microsoft", LogEventLevel.Information)
        .MinimumLevel.Override("Microsoft.EntityFrameworkCore", LogEventLevel.Warning)
        .WriteTo.Async(c => c.Console())
    })
    ....
    .ConfigureAppConfiguration((context, config) => {
        if (!context.HostingEnvironment.IsDevelopment())
        {
            config.AddDockerSecrets(
              options: () => new DockerSecretsConfigurationOptions
              {
                  ColonPlaceholder = "__"
              },
              secretsPath: "/run/secrets",
              logger: new SerilogLoggerProvider(Log.Logger).CreateLogger("DockerSecrets")
          );
        }
    })
    ....
  • Add new GMSSBrandingProvider.cs cs file to project root directory at GridLab.GMSS.AuthServer project.

Copy the wwwroot folder from template folder to the src/GridLab.GMSS.AuthServer folder.

Delete existing logo-dark.png and logo-dark.png logos

[Dependency(ReplaceServices = true)]
public class GMSSBrandingProvider : DefaultBrandingProvider
{
    private IStringLocalizer<GMSSResource> _localizer;

    public GMSSBrandingProvider(IStringLocalizer<GMSSResource> localizer)
    {
        _localizer = localizer;
    }

    public override string AppName => "GMSS Auth Server";

    public override string LogoUrl => "/images/logo/leptonx/logo-light.png";

    public override string LogoReverseUrl => "/images/logo/leptonx/logo-dark.png";
}
  • The versions of npm packages defined in package.json should be checked, where extra npm packages to be used in mvc ui should be defined.
{
  "version": "0.1.0",
  "name": "my-app-authserver",
  "private": true,
  "dependencies": {
    "@volo/abp.aspnetcore.mvc.ui.theme.lepton": "~8.2.0",
    "@volo/account": "~8.2.0"
  }
}

add extra packages if necessary

{
  "version": "0.1.0",
  "name": "my-app-authserver",
  "private": true,
  "dependencies": {
    "@volo/abp.aspnetcore.mvc.ui.theme.lepton": "~8.2.0",
    "@volo/account": "~8.2.0",
    "ace-builds": "^1.4.12",
    "bootstrap-markdown-editor-4": "^3.0.0",
    "jquery-datetimepicker": "^2.5.21",
    "moment": "^2.29.1"
  }
}

In order to run abp install-libs automation scripts, a definition must be made in abp.resourcemapping.js.

module.exports = {
    aliases: {
        "@node_modules": "./node_modules",
        "@libs": "./wwwroot/libs"
    },
    clean: [
        "@libs",
        "!@libs/**/foo.txt"
    ],
    mappings: {
        "@node_modules/bootstrap-markdown-editor-4/dist/css/bootstrap-markdown-editor.min.css": "@libs/bootstrap-markdown-editor-4/css/",
        "@node_modules/bootstrap-markdown-editor-4/dist/js/bootstrap-markdown-editor.min.js": "@libs/bootstrap-markdown-editor-4/js/",
        "@node_modules/ace-builds/src-noconflict/ace.js": "@libs/ace/",
        "@node_modules/ace-builds/src-noconflict/theme-tomorrow.js": "@libs/ace/",
        "@node_modules/ace-builds/src-noconflict/mode-markdown.js": "@libs/ace/",
        "@node_modules/ace-builds/src-noconflict/ext-language_tools.js": "@libs/ace/",
        "@node_modules/moment/moment.js": "@libs/moment/",
        "@node_modules/jquery-datetimepicker/jquery.datetimepicker.js": "@libs/jquery-datetimepicker/",
        "@node_modules/jquery-datetimepicker/jquery.datetimepicker.css": "@libs/jquery-datetimepicker/",
    }
};

Clean wwwroot/libs and node_modules folders for clean installation. This is required action for abp install-libs script.

ABP CLI's abp install-libs command copies resources from node_modules to wwwroot/libs folder. Each standard package (see the @ABP NPM Packages section) defines the mapping for its own files. So, most of the time, you only configure dependencies.

  • Add the following MSBuild instruction to your GridLab.GMSS.AuthServer.csproj file in order to load .pdb files during debugging.
<Target Name="_ResolveCopyLocalNuGetPackagePdbs" Condition="$(CopyLocalLockFileAssemblies) == true" AfterTargets="ResolveReferences">
  <ItemGroup>
    <ReferenceCopyLocalPaths Include="@(ReferenceCopyLocalPaths->'%(RootDir)%(Directory)%(Filename).pdb')" Condition="'%(ReferenceCopyLocalPaths.NuGetPackageId)' != '' and Exists('%(RootDir)%(Directory)%(Filename).pdb')" />
  </ItemGroup>
</Target>