Table of Contents

Class RedisPermissionService

Namespace
KadicAuth.Infrastructure.Services
Assembly
KadicAuth.Infrastructure.dll

GAP-16: Redis-backed IPermissionService for horizontally-scaled deployments. Uses IDistributedCache so the same permission set is shared across all API instances within the configured TTL — eliminates per-instance cache divergence.

Falls back gracefully to fetching from DB when the cache is unavailable (Redis down), never blocking authentication in case of cache failure.

Registration: swap PermissionService for this class in DI when RedisSettings.Enabled = true.

public sealed class RedisPermissionService : IPermissionService
Inheritance
object
RedisPermissionService
Implements
IPermissionService

Constructors

RedisPermissionService(ICurrentUser, IPermissionRepository, IDistributedCache, IOptions<RedisSettings>, ILogger<RedisPermissionService>)

public RedisPermissionService(ICurrentUser currentUser, IPermissionRepository permissionRepository, IDistributedCache distributedCache, IOptions<RedisSettings> redisOptions, ILogger<RedisPermissionService> logger)

Parameters

currentUser ICurrentUser
permissionRepository IPermissionRepository
distributedCache IDistributedCache
redisOptions IOptions<RedisSettings>
logger ILogger<RedisPermissionService>

Methods

GetUserPermissionsAsync(CancellationToken)

Gets all permission codes for the current user based on their roles

public Task<IReadOnlyCollection<string>> GetUserPermissionsAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

Returns

Task<IReadOnlyCollection<string>>

HasPermissionAsync(string, CancellationToken)

Checks if the current user has a specific permission

public Task<bool> HasPermissionAsync(string permissionCode, CancellationToken cancellationToken = default)

Parameters

permissionCode string
cancellationToken CancellationToken

Returns

Task<bool>

InvalidateCacheAsync(Guid, Guid, Guid, CancellationToken)

Invalidates the cached permissions for a specific user/tenant/branch combination.

public Task InvalidateCacheAsync(Guid userId, Guid tenantId, Guid branchId, CancellationToken cancellationToken = default)

Parameters

userId Guid
tenantId Guid
branchId Guid
cancellationToken CancellationToken

Returns

Task

InvalidateTenantCacheAsync(Guid, CancellationToken)

Bumps the tenant's cache-version token, which orphans every permission cache entry currently cached for this tenant across all API instances (their key embeds the old version, so no future read will ever hit them again) — they simply expire on their own via their normal TTL. O(1): no enumeration of affected users, no DB round-trip. Genuinely awaited (not fire-and-forget) so a Redis failure here is logged and visible to the caller's own error handling, instead of being silently lost.

public Task InvalidateTenantCacheAsync(Guid tenantId, CancellationToken cancellationToken = default)

Parameters

tenantId Guid
cancellationToken CancellationToken

Returns

Task