Executando verificação de segurança...
1

Autenticação e Autorização no DDD

Estou estudando DDD e me surgiu uma dúvida de como lido com o conceito de Autenticação com JWT por exemplo e Autorização. Por exmeplo, eu tenho minha parte do dominio referente ao usuário e nela está tudo referente ao usuário, criação/validação do token, etc. Mas em outra parte do sistema, eu preciso do meu token para extrair uma informação para popular meu banco de dados, como funciona essa comunicação sem se perder nos conceitos do DDD?

Carregando publicação patrocinada...
3

Domain Driven Design é uma expressão de modelagem e arquitetura de dados. Você organiza o seu sistema com base em conceitos de domínio e, partir deles, desenvolve seus casos de uso.

Aliás, não existe autenticação com JWT. O padrão JWT é stateless, ou seja, ele guarda uma informação e passa a substituir uma outra. Enquanto ele for válido, a informação contida nele também será. Isso é a referência direta ao sistema de autorização. A autorização nada mais é do que, em referência ao mundo real, uma procuração. Qualquer um com esse "papel" faz o que quiser em seu nome desde que o papel seja válido. Enquanto alguém tiver posse desse papel, acabou, não precisa mais de você.

Esse erro foi muito impulsionado pela geração de cursinhos de programação e uma falta de leitura e bons estudos. Muitos vídeos e conteúdo, aqui, no Youtube e até no Medium, confudem constantemente o conceito.

Autenticação é quando suas credenciais são utilizadas para montar uma sessão que pode ser controlada. Quando você faz entra em um aplicativo, você está se autenticando e tem uma sessão persistente no back-end, geralmente pela troca de cookies. É quando você consegue entrar no app e clicar em "Sair desse dispositivo".

Dado isso, você não autentica um usuário com JWT, você autoriza ele a acessar partes do sistema por um tempo limitado. Em algum momento esse token deverá ser regenerado por razões de segurança e se você precisar trocar a sua senha, por exemplo, o sistema vai pedir para você se autenticar novamente, uma vez que o JWT é impessoal.

JWT's são muito úteis para APIs. Por exemplo, se você quer se conhectar a uma API sem precisar consultar o escopo do cliente no banco de dados a cada conexão. Você compartilha o JWT e baseia todas as restrições de acesso nele, confiando plenamente que aquele é o usuário porque aquele token existe e ele é válido.

Recentemente, precisei emitir relatórios em um sistema. Esses relatórios tinham uma expiração curta e era obrigatório um input de entrada para gerar esse relatório. Nesse caso, JWT se aplica bem, a partir do input de entrada gero o JWT e enquanto o token estiver vivo o relatório será lido. Nem preciso consultar se a pessoa que está usando o token é mesmo quem diz ser, porque se o token for válido, foi emitido e se emitido o relatório pode ser visto. Isso é stateless.

Agora voltando para sua dúvida original. Você tem níveis diferentes camadas de serviços. No domínio de usuário você terá os serviços de emissão autenticação ou autorização recebendo um input de entrada e retornando uma saída. Quando você ler esse token em outro domínio, você irá ter outro serviço de leitura de autenticação ou autorização referente aquele domínio.

No serviço do usuário ficam as regras de negócio de validação do input, garantia que existência do usuário, etc, e a conversão desses dados para um outro dado que represente esse usuário: pode ser um token de sessão (no caso de autenticação) ou um JWT (no caso de autorização). Do outro lado, no servido de pedidos, por exemplo, você irá interpretar o valor de autenticação ou autorização recebidos e ver se essa identificação pode ler os pedidos ou quais ela está autorizada a ler.

Domain-Driven Design é uma coisa bem complexa e leva tempo para aprender, recomendo a leitura do livro Domain-Driven Design: Atacando as Complexidades no Coração do Software. Tem que ler umas três vezes, mas você aprende. Sugiro, entretanto, não implementar em um projeto real sem ter o domínio completo, pois você pode deixar mais complexo do que realmente é.

2

Mas em outra parte do sistema, eu preciso do meu token para extrair uma informação para popular meu banco de dados, como funciona essa comunicação sem se perder nos conceitos do DDD?

Não sei como você está modelando esse sistema, mas o token de autenticação não deveria ser usado pelo que acontece para "trás" da autenticação.

Se for um sistema de pedidos por exemplo, o processo do pedido deve receber um usuário, ou a matricula/id dele para realizar sua operações internas. E não o token de autenticação.

1

Vamos supor que tenho que eu tenha a parte dos pedidos, para salvar no banco eu preciso do ID do usuário que está no token. Faz sentindo o front enviar essa informação do que eu extrair do token?

3

Não sei quais tecnologias você está usando no seu projeto, vou dar um exemplo de um projeto que estou atuando nesse momento em Node, Express e TypeScript. Apesar dele não estar centrado no DDD.


Tenho um types.d.ts no diretório src para indicar ao TypeScript que estou adicionando uma propriedade aos tipos existentes do Express.

declare namespace Express {
  export interface Request {
    userId: number;    
  }

  export interface JwtPayload {
    userId: number;
  }
}

Meu middleware de autenticação, vai validar o token, e em caso de sucesso ele trata e define o userId na requisição.

export const authMiddleware = (
  req: Request,
  res: Response,
  next: NextFunction
): Response | NextFunction | void => {
  if (req.path === '/login' || req.path === '/refresh-token') {
    next();
  } else {
    let token = req.headers['x-access-token'] as string;

    if (!token) {
        return res.sendStatus(403);
     }
    
    const secret = process.env.JWT_SECRET || 'secret';

    try {
      const decoded = jwt.verify(token, secret) as jwt.JwtPayload;

      req.userId = decoded.userId;
      next();
    } catch (error) {
      return res.sendStatus(401);
    }
  }
};

Ou seja, da autentição em diante eu não preciso do token para nada.
Aí posso usar o userId conforme necessário.

router.get(`/relatorios/:tipo`, async (req: Request, res: Response) => {
    const matricula = req.userId;    
    // Restante do código aqui
});

Veja, esse é um exemplo simples, é claro que no decorrer desse projeto existem outras validações em cima dessa informação. Mas o core da sua aplicação não pode depender do que acontece na camada HTTP, nesse caso eu me refiro ao JWT.

Se você criar um CLI para tarefas administrativas por exemplo, se houver autenticação pode ser que seja diferente, e a camada de autenticação dessa interface CLI tem que traduzir essa autenticação em um userId.

Sua camada de negócio vai receber um userId, como isso chegou lá não é de interesse dessa camada. Captou?

2

devig0r, DDD seria Domain-Driven Design?

Basicamente, DDD é uma abordagem de desenvolvimento de software que coloca o foco no entendimento profundo de negócios. Em vez de começar pelo código ou pela tecnologia, prioriza-se a compreensão de regras, processos e conceitos da empresa que a aplicação é destinada a atender.
Fonte

Aproveitando o ímpeto, fui também procurar saber o que é a sigla JWT.

JWT é um padrão aberto de mercado definido pela RFC 7519 como um formato compacto e autossuficiente para transmitir informações entre as partes como um objeto JSON. O recurso é frequentemente usado na autenticação e na autorização em aplicativos da web e móveis.
Fonte