UDT-002: Logout + Refresh Token con rotación y chain revocation #3
63
database/migrations/V002__create_refresh_token.sql
Normal file
63
database/migrations/V002__create_refresh_token.sql
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
-- V002__create_refresh_token.sql
|
||||||
|
-- Creates dbo.RefreshToken table for opaque token rotation with chain revocation
|
||||||
|
-- Run on: SIGCM2 (prod) and SIGCM2_Test (integration tests)
|
||||||
|
|
||||||
|
SET QUOTED_IDENTIFIER ON;
|
||||||
|
SET ANSI_NULLS ON;
|
||||||
|
GO
|
||||||
|
|
||||||
|
IF OBJECT_ID(N'dbo.RefreshToken', N'U') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
PRINT 'Table dbo.RefreshToken already exists — skipping.';
|
||||||
|
RETURN;
|
||||||
|
END
|
||||||
|
GO
|
||||||
|
|
||||||
|
CREATE TABLE dbo.RefreshToken
|
||||||
|
(
|
||||||
|
Id INT IDENTITY(1,1) NOT NULL,
|
||||||
|
UsuarioId INT NOT NULL,
|
||||||
|
TokenHash NVARCHAR(88) NOT NULL, -- SHA-256 base64url = 43 chars sin padding; margen a 88
|
||||||
|
FamilyId UNIQUEIDENTIFIER NOT NULL, -- una familia = una sesion de login
|
||||||
|
IssuedAt DATETIME2(3) NOT NULL,
|
||||||
|
ExpiresAt DATETIME2(3) NOT NULL, -- absolute: heredado en cada rotacion
|
||||||
|
RevokedAt DATETIME2(3) NULL,
|
||||||
|
ReplacedById INT NULL,
|
||||||
|
CreatedByIp VARCHAR(45) NOT NULL, -- IPv4/IPv6 textual
|
||||||
|
UserAgent NVARCHAR(512) NULL,
|
||||||
|
|
||||||
|
CONSTRAINT PK_RefreshToken PRIMARY KEY CLUSTERED (Id),
|
||||||
|
CONSTRAINT FK_RefreshToken_Usuario
|
||||||
|
FOREIGN KEY (UsuarioId) REFERENCES dbo.Usuario(Id),
|
||||||
|
CONSTRAINT FK_RefreshToken_ReplacedBy
|
||||||
|
FOREIGN KEY (ReplacedById) REFERENCES dbo.RefreshToken(Id),
|
||||||
|
CONSTRAINT UQ_RefreshToken_TokenHash UNIQUE (TokenHash)
|
||||||
|
);
|
||||||
|
GO
|
||||||
|
|
||||||
|
-- Lookup por familia para chain revocation
|
||||||
|
CREATE INDEX IX_RefreshToken_UsuarioId_FamilyId
|
||||||
|
ON dbo.RefreshToken (UsuarioId, FamilyId);
|
||||||
|
GO
|
||||||
|
|
||||||
|
-- Indice filtrado para revocaciones masivas de activos
|
||||||
|
CREATE INDEX IX_RefreshToken_Active
|
||||||
|
ON dbo.RefreshToken (UsuarioId, FamilyId)
|
||||||
|
WHERE RevokedAt IS NULL;
|
||||||
|
GO
|
||||||
|
|
||||||
|
-- Housekeeping futuro
|
||||||
|
CREATE INDEX IX_RefreshToken_ExpiresAt
|
||||||
|
ON dbo.RefreshToken (ExpiresAt)
|
||||||
|
WHERE RevokedAt IS NULL;
|
||||||
|
GO
|
||||||
|
|
||||||
|
EXEC sys.sp_addextendedproperty
|
||||||
|
@name = N'MS_Description',
|
||||||
|
@value = N'Refresh tokens opacos (SHA-256 hash) con rotacion y chain revocation por familia',
|
||||||
|
@level0type = N'SCHEMA', @level0name = N'dbo',
|
||||||
|
@level1type = N'TABLE', @level1name = N'RefreshToken';
|
||||||
|
GO
|
||||||
|
|
||||||
|
PRINT 'Table dbo.RefreshToken created successfully.';
|
||||||
|
GO
|
||||||
Reference in New Issue
Block a user