Repository navigation
Cadastrar usuários e autenticar com JWT, exigindo token nos demais endpoints - #30
Merged
Merged
Conversation
…o de dados e fuso horário
…stes de integração
…ivação e tratar cadastros simultâneos com o mesmo e-mail
…ller e exigir token nos demais endpoints
…figurar a chave do JWT em produção
…dos pacotes e acrescentando os pacotes de autenticação
…ta de inativação nos testes de usuário
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Esta branch adiciona usuários e autenticação à API. É possível se cadastrar e entrar com e-mail e senha, recebendo um token JWT, e todos os endpoints de negócio passam a exigir esse token. A senha é guardada com Argon2id. Um usuário inativado há até 30 dias pode voltar a se cadastrar com a mesma senha e é reativado. O CD passa a aplicar o
main.bicepquando a infraestrutura muda, o que leva a chave do JWT para produção.Mudanças
Hash de senha
IPasswordHashing(Domain) eArgon2PasswordHasher(Infrastructure), com o pacoteKonscious.Security.Cryptography.Argon2. O hash guarda salt aleatório e hash juntos em Base64, e a verificação compara em tempo constante (CryptographicOperations.FixedTimeEquals).Entidade
Usere bancoUsersegue o padrão doPolicyholder: construtor com validação de nome (até 150 caracteres), e-mail normalizado e senha obrigatória,Updateque valida tudo antes de alterar,DeactivateeReactivate.DeactivatedAtregistra quando o usuário foi inativado, eCanBeReactivatedaplica o prazo de 30 dias (User.ReactivationPeriod).userscom e-mail único entre os usuários ativos (IX_users_email_active), filtro global de inativos e concorrência otimista porxmin. A colunapasswordétext, sem limite.CreateUserseAddUserDeactivatedAt. ACreateUserstambém atualiza o snapshot do modelo, que ainda registravaBirthDate,StartDate,EndDateeOccurredOncomoDateTime; as colunas não mudam.Repositório de usuários
IUsersWriteOnlyRepository,IUsersReadOnlyRepositoryeIUsersUpdateOnlyRepository, implementados peloUsersRepository: cadastro, busca por id e por e-mail, verificação de e-mail em uso, busca incluindo inativos e busca do último usuário inativado com um e-mail.Cadastro
POST /api/autenticacao/registrarrecebenome,emailesenhae devolve 201 com oid.iddele é devolvido; se não conferir, a resposta é 400 com "E-mail ou senha inválidos.". Depois de 30 dias, um usuário novo é criado.UnitOfWorktransforma o erro do banco na mesma mensagem de e-mail em uso, em vez de um 500.Login e JWT
POST /api/autenticacao/entrarrecebeemailesenhae devolve 200 comnome,tokeneexpiraEm.sube umjtiúnico. Issuer, audience e validade (60 minutos) ficam na seçãoJwtdoappsettings.json. A chave (Jwt:SigningKey, mínimo de 32 bytes) fica fora do repositório e é validada na inicialização, como as demais opções.AuthenticationController.Autorização
registrar,entrar,/health, o documento OpenAPI e o redirecionamento da raiz para o Swagger.errorse otraceId.TimeProviderda aplicação, o mesmo relógio que o gera.Infraestrutura e CD
main.biceprecebe o parâmetro segurojwtSigningKeye o grava no App Service comoJwt__SigningKey.cd.ymlganhou o jobinfra, que aplica omain.bicepsó quando o push alterainfra/main.bicepouinfra/bootstrap.sh. Ele roda antes do deploy e mantém a imagem que já está no ar, para que o código novo só suba depois das migrations.bootstrap.shgera a chave do JWT, grava os secretsDATABASE_ADMIN_PASSWORDeJWT_SIGNING_KEYe a variávelAZURE_RESOURCE_GROUP, e dá à identidade do GitHub o papelContributorno resource group, no lugar deWebsite Contributorno Web App.docker/compose.ymltraz uma chave padrão só para uso local, e o README mostra como configurá-la comdotnet user-secrets.Authorization: Bearer <token>.main: rode./infra/bootstrap.shuma vez. Sem os novos secrets e a nova permissão, o jobinfrafalha e o deploy não acontece. O bootstrap também gera uma nova senha do banco e uma nova chave do JWT, então tokens emitidos antes deixam de valer.Website Contributorno Web App paraContributorno resource group, porque o Bicep também gerencia o banco e o plano.Jwt:SigningKeycom pelo menos 32 bytes, a API não sobe. Localmente, usedotnet user-secrets set "Jwt:SigningKey" "$(openssl rand -base64 48)" --project src/Backend/PolicyDesk.Api.Konscious.Security.Cryptography.Argon21.3.1,Microsoft.AspNetCore.Authentication.JwtBearer10.0.14 eMicrosoft.IdentityModel.JsonWebTokens8.19.2.Como testar
docker compose -f docker/compose.yml -f docker/compose.dev.yml up -d --builde abra o Swagger.GET /api/seguradossem token: deve responder 401.POST /api/autenticacao/registrare entre emPOST /api/autenticacao/entrar.tokene repita oGET /api/segurados: deve responder 200.active = false,deactivated_at = now()) e cadastre o mesmo e-mail com a mesma senha: deve responder 201 com o mesmoid. Com outra senha, deve responder 400.Testes
Argon2PasswordHasherTests: formato do hash, salt diferente a cada hash, senha certa, senha diferente, só com maiúsculas trocadas e com espaço a mais;UsersTests: criação, validação de nome, e-mail e senha,Updatesem alterar nada quando algo é inválido, inativação e prazo de reativação;UsersRepositoryTests: cadastro e consultas, inativos fora das buscas, último inativo por e-mail e cadastro simultâneo com o mesmo e-mail;RegisterUserUseCaseTestseLoginUseCaseTests: validações, senha guardada como hash, e-mail em uso, reativação dentro e fora do prazo, credenciais inválidas;JwtAccessTokenGeneratorTests: token validado de verdade,sub, validade, tokens diferentes e recusa com outra chave;/healthaberto e esquema Bearer no OpenAPI só nas rotas protegidas;CommonTestUtilities:UserBuilder,PasswordGenerator,PasswordHashingBuilder,RequestUserJsonBuilder,RequestLoginJsonBuilder,JwtOptionsBuilder,AccessTokenGeneratorBuildere os mocks do repositório de usuários.