Laqus.Platform.Auth 2.8.1

dotnet add package Laqus.Platform.Auth --version 2.8.1
                    
NuGet\Install-Package Laqus.Platform.Auth -Version 2.8.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Laqus.Platform.Auth" Version="2.8.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Laqus.Platform.Auth" Version="2.8.1" />
                    
Directory.Packages.props
<PackageReference Include="Laqus.Platform.Auth" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Laqus.Platform.Auth --version 2.8.1
                    
#r "nuget: Laqus.Platform.Auth, 2.8.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Laqus.Platform.Auth@2.8.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Laqus.Platform.Auth&version=2.8.1
                    
Install as a Cake Addin
#tool nuget:?package=Laqus.Platform.Auth&version=2.8.1
                    
Install as a Cake Tool

Laqus Platform Auth

Pacote NuGet para integração de serviços com o sistema de autenticação e autorização da plataforma Laqus.


Setup

Configuração (appsettings)

"LaqusAuth": {
  "AuthMiddlewareApiUrl": "http://localhost:3030/",
  "Cache": {
    "Ttl": 3600,
    "EnableTls": false,
    "RedisUser": "",
    "RedisPassword": "",
    "RedisHost": "localhost",
    "RedisPort": 6379,
    "AuthCacheKeysPrefix": ""
  },
  "Keycloak": {
    "Authority": "http://localhost:9990/realms/laqus-platform",
    "ClientId": "my-tenant-api-client",
    "Issuer": "http://localhost:9990/realms/laqus-platform",
    "ClientSecret": "********************"
  }
}

Registro dos Serviços

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddLaqusAuth(builder.Configuration, option =>
{
    option.AppName = "App Teste";
    option.AuthMiddlewareApiUrl = builder.Configuration["LaqusAuth:AuthMiddlewareApiUrl"];
    option.Options = new AuthOptions
    {
        Authority = builder.Configuration["LaqusAuth:Keycloak:Authority"],
        ClientId = builder.Configuration["LaqusAuth:Keycloak:ClientId"],
        ClientSecret = builder.Configuration["LaqusAuth:Keycloak:ClientSecret"],
        Issuer = builder.Configuration["LaqusAuth:Keycloak:Issuer"],
    };
    option.CacheOptions = new CacheOptions
    {
        Ttl = int.Parse(builder.Configuration["LaqusAuth:Cache:Ttl"] ?? "3600"),
        EnableTls = builder.Configuration["LaqusAuth:Cache:EnableTls"] == "true",
        RedisUser = builder.Configuration["LaqusAuth:Cache:RedisUser"],
        RedisPassword = builder.Configuration["LaqusAuth:Cache:RedisPassword"],
        RedisHost = builder.Configuration["LaqusAuth:Cache:RedisHost"],
        RedisPort = int.Parse(builder.Configuration["LaqusAuth:Cache:RedisPort"]!),
        AuthCacheKeysPrefix = builder.Configuration["LaqusAuth:Cache:AuthCacheKeysPrefix"]
    };
});

Pipeline de Middlewares

var app = builder.Build();
app.UseRouting();

app.UseAuthentication();
app.UseLaqusLegacySSOAuthenticationMiddleware();
app.UseAuthorization();

// Opção 1: Autorização completa + tratamento de erros JWT
app.UseLaqusAuthorization();

// Opção 2: Apenas autorização (sem tratamento de erros JWT)
app.UseLaqusAuthorizationMiddleware();

// Opção 3: Apenas tratamento de erros JWT (sem autorização)
app.UseLaqusJwtErrorHandler();

app.MapControllers();

Usuário Autenticado

Acesse informações do usuário logado via IPlatformAuthService:

public class MyController : ControllerBase
{
    private readonly IPlatformAuthService _platformAuthService;

    public MyController(IPlatformAuthService platformAuthService)
    {
        _platformAuthService = platformAuthService;
    }

    [HttpGet("current-user")]
    [IsAuthenticated]
    public IActionResult GetCurrentUser()
    {
        if (!_platformAuthService.IsUserAuthenticated)
            return Unauthorized();

        return Ok(new
        {
            Token = _platformAuthService.TokenInfo.Token,
            User = _platformAuthService.AuthenticatedUser
        });
    }
}

Autorização por Actions

Actions são permissões granulares baseadas em LRN (Laqus Resource Name) e operações.

  • LRN: lrn:laqus:v1::<domínio>/<subdomínio>/<...>/<subdomínio>:<recurso>
  • Action: Operação específica (criar, consultar, atualizar, excluir)

As actions estão centralizadas na classe estática PlatformActions:

using Laqus.Platform.Auth.Authorization;

PlatformActions.Securitizacao.Termos.Criar
PlatformActions.Securitizacao.Termos.Consultar
PlatformActions.Securitizacao.Termos.Atualizar
PlatformActions.Securitizacao.Termos.Excluir
PlatformActions.Securitizacao.Termos.ConsultarGlobal
PlatformActions.Securitizacao.Termos.Anexos.Criar
PlatformActions.Escrituracao.Auditoria.Logs.Consultar

Decorators

[RequireAction] — Protegendo Endpoints
using Laqus.Platform.Auth.Authorization;
using Laqus.Platform.Auth.Decorators;
using Microsoft.AspNetCore.Mvc;

[ApiController]
[Route("api/[controller]")]
public class CadastrosController : ControllerBase
{
    [HttpGet]
    [RequireAction(PlatformActions.Cadastro.Cadastros.ListBase)]
    public async Task<IActionResult> ListCadastros()
    {
        return Ok(await GetCadastros());
    }
}
Múltiplas Actions (AND)

Por padrão, todas as actions devem ser satisfeitas (estratégia ALL):

[HttpPost("cadastros/{id}/approve")]
[RequireAction(
    PlatformActions.Cadastro.Cadastros.Update,
    PlatformActions.Cadastro.Cadastros.Administrar
)]
public async Task<IActionResult> ApproveCadastro(Guid id)
{
    return Ok();
}
Controller vs Método

O atributo pode ser aplicado no controller (afeta todos os métodos) e sobrescrito por método:

[ApiController]
[Route("api/[controller]")]
[RequireAction(PlatformActions.Cadastro.Cadastros.GetBase)]
public class CadastrosController : ControllerBase
{
    [HttpGet]
    public async Task<IActionResult> List()
    {
        // Usa a action do controller: GetBase
        return Ok();
    }

    [HttpPost]
    [RequireAction(PlatformActions.Cadastro.Cadastros.Create)]
    public async Task<IActionResult> Create()
    {
        // Sobrescreve com a action do método: Create
        return Ok();
    }
}
[IsPublic] e [IsAuthenticated]
[HttpPost("login")]
[IsPublic]
public async Task<IActionResult> Login([FromBody] LoginDto dto)
{
    // Endpoint público, sem autenticação
    return Ok();
}

[HttpGet("profile")]
[IsAuthenticated]
public async Task<IActionResult> GetProfile()
{
    // Requer apenas autenticação, sem validação de permissões
    return Ok();
}

Validação Programática

Para lógica condicional complexa, use IPlatformAuthorizationService:

using Laqus.Platform.Auth.LaqusAuthMiddleware.Service;
using Laqus.Platform.Auth.Authorization;

public class CadastrosApplicationService
{
    private readonly IPlatformAuthorizationService _authorizationService;

    public CadastrosApplicationService(
        IPlatformAuthorizationService authorizationService)
    {
        _authorizationService = authorizationService;
    }
}
Action Única
public async Task<IActionResult> ProcessarCadastro(Guid cadastroId)
{
    var hasPermission = await _authorizationService.AuthorizeAsync(
        PlatformActions.Cadastro.Cadastros.Update
    );

    if (!hasPermission)
        throw new ForbiddenException("Usuário sem permissão para atualizar cadastros");

    // Continua processamento...
}
Múltiplas Actions (ALL / ANY)
// Estratégia ALL — todas as actions são necessárias
var hasAll = await _authorizationService.AuthorizeAsync(
    new[]
    {
        PlatformActions.Cadastro.Cadastros.Update,
        PlatformActions.Cadastro.Cadastros.Administrar
    },
    AuthorizationStrategy.ALL
);

// Estratégia ANY — pelo menos uma das actions
var hasAny = await _authorizationService.AuthorizeAsync(
    new[]
    {
        PlatformActions.Cadastro.Cadastros.GetBase,
        PlatformActions.Cadastro.Cadastros.GetDetails
    },
    AuthorizationStrategy.ANY
);
Validação de User Type
using Laqus.Platform.Auth.LaqusAuthMiddleware.Models.Authorization;

var isServiceAccount = await _authorizationService.AuthorizeApiServiceAccountAsync();
var isRegularUser = await _authorizationService.AuthorizeRegularUserAsync();
Exemplo: Resposta Condicional por Permissão
public async Task<CadastroDto> GetCadastro(Guid cadastroId)
{
    var cadastro = await _cadastroService.GetByIdAsync(cadastroId);
    var dto = _mapper.Map<CadastroDto>(cadastro);

    var canViewSensitiveData = await _authorizationService.AuthorizeAsync(
        PlatformActions.Cadastro.Cadastros.GetDetails
    );

    if (!canViewSensitiveData)
    {
        dto.DadosBancarios = null;
        dto.DocumentosPessoais = null;
    }

    return dto;
}

Gerenciamento de Políticas

Use IAuthMiddlewareUsersProxy (registrado automaticamente por AddLaqusAuth) para gerenciar usuários e permissões via código.

Actions = Permissões granulares por recurso | Policies = Agrupamentos de actions (ex: "Admin", "Reader")

public class UserPermissionService
{
    private readonly IAuthMiddlewareUsersProxy _usersProxy;

    public UserPermissionService(IAuthMiddlewareUsersProxy usersProxy)
    {
        _usersProxy = usersProxy;
    }
}

Atribuir Políticas

using Laqus.Platform.Auth.Authorization;
using Laqus.Platform.Auth.LaqusAuthMiddleware.Proxy.Users.Dtos.Request;

// Por nome
var assignDto = new AssignUserPoliciesDto
{
    PoliciesNames = new[]
    {
        PlatformPolicies.AccountManagement.User.Admin,
        PlatformPolicies.Cadastro.CadastrosEditor
    }
};
await _usersProxy.AssignPoliciesToUserAsync(userId, assignDto);

// Por ID
var assignById = new AssignUserPoliciesDto { PoliciesIds = policyIds };
await _usersProxy.AssignPoliciesToUserAsync(userId, assignById);

// Via grupo
var assignViaGroup = new AssignUserPoliciesDto
{
    GroupId = groupId,
    PoliciesNames = new[] { PlatformPolicies.Cadastro.CadastrosReader }
};
await _usersProxy.AssignPoliciesToUserAsync(userId, assignViaGroup);

Consultar e Remover Políticas

// Consultar
var response = await _usersProxy.GetUserPoliciesAsync(userId);
if (!response.Success)
    throw new InvalidOperationException($"Falha ao buscar políticas: {response.Message}");
var policies = response.Result;

// Remover
using Laqus.Platform.Auth.LaqusAuthMiddleware.Proxy.Users.Dtos.Request;

var removeDto = new RemovePoliciesFromUserDto
{
    PoliciesNames = new[] { PlatformPolicies.Cadastro.CadastrosEditor }
};
await _usersProxy.RemovePoliciesFromUserAsync(userId, removeDto);

Gerenciamento de Status

await _usersProxy.SetUserStatusAsync(userId, active: true);
await _usersProxy.SetUserStatusAsync(userId, active: false);

Exemplo Completo — Onboarding

public class UserOnboardingService
{
    private readonly IAuthMiddlewareUsersProxy _usersProxy;
    private readonly ILogger<UserOnboardingService> _logger;

    public UserOnboardingService(
        IAuthMiddlewareUsersProxy usersProxy,
        ILogger<UserOnboardingService> logger)
    {
        _usersProxy = usersProxy;
        _logger = logger;
    }

    public async Task<Guid> CreateUserWithBasicPermissions(
        string email, string firstName, string lastName)
    {
        _logger.LogInformation("Creating user {Email}", email);

        var createResponse = await _usersProxy.CreateUserAsync(new CreateUserDto
        {
            Email = email, FirstName = firstName,
            LastName = lastName, Enabled = true
        });

        if (!createResponse.Success)
            throw new InvalidOperationException(
                $"Falha ao criar usuário: {createResponse.Message}");

        var userId = createResponse.Result.Id;

        await _usersProxy.AssignPoliciesToUserAsync(userId, new AssignUserPoliciesDto
        {
            PoliciesNames = new[]
            {
                PlatformPolicies.Cadastro.CadastrosReader,
                PlatformPolicies.Cadastro.DocumentosReader
            }
        });

        _logger.LogInformation("User {UserId} created with basic permissions", userId);
        return userId;
    }

    public async Task PromoteToEditor(Guid userId)
    {
        await _usersProxy.AssignPoliciesToUserAsync(userId, new AssignUserPoliciesDto
        {
            PoliciesNames = new[]
            {
                PlatformPolicies.Cadastro.CadastrosEditor,
                PlatformPolicies.Cadastro.DocumentosEditor
            }
        });
        _logger.LogInformation("User {UserId} promoted to editor", userId);
    }

    public async Task RevokeEditorPermissions(Guid userId)
    {
        await _usersProxy.RemovePoliciesFromUserAsync(userId, new RemovePoliciesFromUserDto
        {
            PoliciesNames = new[]
            {
                PlatformPolicies.Cadastro.CadastrosEditor,
                PlatformPolicies.Cadastro.DocumentosEditor
            }
        });
        _logger.LogInformation("Editor permissions revoked from user {UserId}", userId);
    }
}

Tratamento de Erros e Personalização

Respostas de Erro

A biblioteca retorna JSON estruturado com os códigos HTTP apropriados:

HTTP Status Código Quando
401 Unauthorized AUTH_REQUIRED Usuário não autenticado
401 Unauthorized TOKEN_INVALID Token JWT inválido
401 Unauthorized TOKEN_EXPIRED Token JWT expirado
403 Forbidden INSUFFICIENT_PERMISSIONS Permissões insuficientes
403 Forbidden ROLE_REQUIRED Função específica necessária
403 Forbidden ACTION_REQUIRED Ação específica necessária
403 Forbidden USER_TYPE_REQUIRED Tipo de usuário incompatível

Formato da resposta:

{
  "codigo": "AUTH_REQUIRED",
  "mensagem": "Autenticação necessária",
  "detalhes": "Esta operação requer que você esteja autenticado."
}

Personalização de Mensagens

builder.Services.AddLaqusAuthorization(options =>
{
    options.ErrorMessages.AuthenticationRequired = "Autenticação necessária";
    options.ErrorMessages.AuthenticationRequiredDetails = "Você precisa estar logado para acessar este recurso.";
    options.ErrorMessages.InsufficientPermissions = "Permissão negada";
    options.ErrorMessages.ActionRequired = "Permissão insuficiente";
    options.ErrorMessages.TokenInvalid = "Token inválido";
    options.ErrorMessages.TokenInvalidDetails = "O token fornecido é inválido ou mal-formado.";
    options.ErrorMessages.TokenExpired = "Sua sessão expirou";
    options.ErrorMessages.TokenExpiredDetails = "Por favor, faça login novamente.";
});

Todas as propriedades personalizáveis:

Propriedade Descrição
AuthenticationRequired / AuthenticationRequiredDetails Autenticação necessária
InsufficientPermissions / InsufficientPermissionsDetails Permissões insuficientes
RoleRequired / RoleRequiredDetails Função necessária
ActionRequired / ActionRequiredDetails Ação necessária
UserTypeRequired / UserTypeRequiredDetails Tipo de usuário incompatível
TokenInvalid / TokenInvalidDetails Token JWT inválido
TokenExpired / TokenExpiredDetails Token JWT expirado

🔐 Redis ACL (Redis 6+ / Valkey)

A partir da versão 2.8.0, a lib suporta autenticação Redis via ACL (AUTH username password).

🆕 Propriedade RedisUser

Propriedade Tipo Obrigatória Descrição
RedisUser string ❌ Não Username para autenticação ACL no Redis/Valkey

🧩 Como funciona

CacheOptions.RedisUser
        ↓
connection string: ,user=<username>
        ↓
ConfigurationOptions.Parse(...)
        ↓
ConfigurationOptions.User
        ↓
Redis/Valkey: AUTH <username> <password>

📝 Exemplo de configuração

"Cache": {
  "RedisUser": "laqus-auth",
  "RedisPassword": "my-secret",
  "RedisHost": "valkey.internal",
  "RedisPort": 6379
}

✅ Retrocompatibilidade

  • RedisUser = null ou "" → comportamento idêntico ao anterior (sem user= na connection string)
  • Nenhuma alteração necessária para consumidores existentes

⚠️ Pontos de Atenção

  1. LRN Case-Sensitive — Use exatamente como definido em PlatformActions.
  2. Decorators vs Programática — Decorators para proteção de rotas; programática para lógica condicional complexa.
  3. Validação em Runtime — Ocorre no middleware, antes do controller. Sem overhead no método.
  4. Cache (Redis) — Permissões são cacheadas. Configure o TTL adequado e considere-o ao validar alterações recentes.
  5. PerformanceAuthorizeAsync consulta cache, mas evite chamadas excessivas em loops.
  6. Idempotência — Atribuir a mesma política múltiplas vezes não gera erro.
  7. Transações — Operações de atribuição/remoção de políticas são individuais. Implemente compensação se necessário.
  8. Permissões para gerenciar políticas — O usuário precisa de PlatformActions.AccountManagement.User.Policies.Assign e .Unassign.
  9. Exception Handling — Lance exceções específicas (ForbiddenException, UnauthorizedException). Trate HttpRequestException ao comunicar com o Auth Middleware.
  10. Testing — Use tokens JWT válidos ou mocke IPlatformAuthService.
  11. Logging — Sempre logue operações de atribuição/remoção de permissões para auditoria.

Checklist Rápido

Autorização por Actions:

  • using Laqus.Platform.Auth.Authorization; e using Laqus.Platform.Auth.Decorators;
  • [RequireAction(PlatformActions...)] nos endpoints
  • [IsAuthenticated] ou [IsPublic] onde aplicável

Gerenciamento de Políticas:

  • Injetar IAuthMiddlewareUsersProxy
  • Usar constantes de PlatformPolicies
  • Tratamento de erros e logging

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 is compatible. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.8.1 114 8/24/2026
2.8.0 151 8/14/2026
2.7.1 98 8/12/2026
2.7.0 109 7/31/2026
2.6.0 104 7/28/2026
2.5.0 253 7/20/2026
2.4.0 102 7/16/2026
2.3.0 234 7/1/2026
2.2.2 282 6/15/2026
2.2.1 111 6/12/2026
2.2.0 117 6/2/2026
2.1.3 118 6/1/2026
2.1.2 173 5/13/2026
2.1.1 243 4/14/2026
2.1.0 111 4/14/2026
2.0.1 112 4/13/2026
2.0.0 141 4/7/2026
1.1.0 198 3/10/2026
1.0.18 994 10/14/2025
1.0.17 261 9/23/2025
Loading failed