diff --git a/src/main/java/com/minsait/api/controller/ApiController.java b/src/main/java/com/minsait/api/controller/ApiController.java index 88a78c0..44fbb25 100644 --- a/src/main/java/com/minsait/api/controller/ApiController.java +++ b/src/main/java/com/minsait/api/controller/ApiController.java @@ -3,21 +3,28 @@ import com.minsait.api.controller.dto.ClienteRequest; import com.minsait.api.controller.dto.ClienteResponse; import com.minsait.api.controller.dto.MessageResponse; +import com.minsait.api.controller.dto.UsuarioRequest; +import com.minsait.api.controller.dto.UsuarioResponse; import com.minsait.api.repository.ClienteEntity; import com.minsait.api.repository.ClienteRepository; +import com.minsait.api.repository.UsuarioEntity; +import com.minsait.api.repository.UsuarioRepository; import com.minsait.api.util.ObjectMapperUtil; import lombok.extern.slf4j.Slf4j; + +import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PostAuthorize; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.web.bind.annotation.*; import java.time.LocalDateTime; +import java.util.Objects; @Slf4j @RestController @@ -26,6 +33,9 @@ public class ApiController implements ApiSwagger{ @Autowired private ClienteRepository clienteRepository; + + @Autowired + private UsuarioRepository usuarioRepository; @PreAuthorize("hasAuthority('LEITURA_CLIENTE')") @GetMapping("/cliente") @@ -104,4 +114,103 @@ public ResponseEntity findById(@PathVariable Long id){ return new ResponseEntity<>(clienteResponse, HttpStatus.OK); } + + @PreAuthorize("hasAuthority('LEITURA_USUARIO')") + @GetMapping("/usuario") + public ResponseEntity> usuarioFindAll(@RequestParam(required = false) String nome, + @RequestParam(required = false) String login, + @RequestParam(required = false) String email, + @RequestParam(required = false, defaultValue = "0") int page, + @RequestParam(required = false, defaultValue = "10") int pageSize) { + final var usuarioEntity = new UsuarioEntity(); + usuarioEntity.setNome(nome); + usuarioEntity.setLogin(login); + usuarioEntity.setEmail(email); + + Pageable pageable = PageRequest.of(page, pageSize); + + final Page usuarioEntityListPage = usuarioRepository.findAll( + usuarioEntity.usuarioEntitySpecification(), pageable); + final Page usuarioResponseList = ObjectMapperUtil.mapAll(usuarioEntityListPage, + UsuarioResponse.class); + return ResponseEntity.ok(usuarioResponseList); + } + + @PreAuthorize("hasAuthority('ESCRITA_USUARIO')") + @PostMapping("/usuario") + public ResponseEntity insertUsuario(@RequestBody UsuarioRequest request){ + + BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + + final var usuarioEntity = ObjectMapperUtil.map(request, UsuarioEntity.class); + + final var senhaEncoded = passwordEncoder.encode(usuarioEntity.getSenha()); + usuarioEntity.setSenha(senhaEncoded); + + final var usuarioInserted = usuarioRepository.save(usuarioEntity); + final var usuarioResponse = ObjectMapperUtil.map(usuarioInserted, UsuarioResponse.class); + + return new ResponseEntity<>(usuarioResponse, HttpStatus.CREATED); + } + + @PreAuthorize("hasAuthority('ESCRITA_USUARIO')") + @PutMapping("/usuario") + public ResponseEntity updateUsuario(@RequestBody UsuarioRequest request){ + final var usuarioEntity = ObjectMapperUtil.map(request, UsuarioEntity.class); + final var usuarioEntityFound = usuarioRepository.findById(usuarioEntity.getId()); + + if (usuarioEntityFound.isPresent()) { + BeanUtils.copyProperties(usuarioEntity, usuarioEntityFound.get(), "senha"); + + if (Objects.nonNull(usuarioEntity.getSenha()) && !usuarioEntity.getSenha().isBlank()) { + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + String senhaEncoded = encoder.encode(usuarioEntity.getSenha()); + usuarioEntityFound.get().setSenha(senhaEncoded); + } + + final var usuarioUpdated = usuarioRepository.save(usuarioEntityFound.get()); + final var usuarioResponse = ObjectMapperUtil.map(usuarioUpdated, UsuarioResponse.class); + + return new ResponseEntity<>(usuarioResponse, HttpStatus.OK); + } else { + return new ResponseEntity<>(new UsuarioResponse(), HttpStatus.NOT_FOUND); + } + } + + @PreAuthorize("hasAuthority('ESCRITA_USUARIO')") + @DeleteMapping("/usuario/{id}") + public ResponseEntity deleteUsuario(@PathVariable Long id){ + final var usuarioEntityFound = usuarioRepository.findById(id); + if(usuarioEntityFound.isPresent()){ + usuarioRepository.delete(usuarioEntityFound.get()); + }else{ + return new ResponseEntity<>(MessageResponse.builder() + .message("Usuário não encontrado!") + .date(LocalDateTime.now()) + .error(false) + .build(), HttpStatus.NOT_FOUND); + } + + return new ResponseEntity<>(MessageResponse.builder() + .message("OK") + .date(LocalDateTime.now()) + .error(false) + .build(), HttpStatus.OK); + } + + @PreAuthorize("hasAuthority('LEITURA_USUARIO')") + @GetMapping("/usuario/{id}") + public ResponseEntity usuarioFindById(@PathVariable Long id){ + final var usuarioEntity = usuarioRepository.findById(id); + UsuarioResponse usuarioResponse = new UsuarioResponse(); + + if (usuarioEntity.isPresent()){ + usuarioResponse = ObjectMapperUtil.map(usuarioEntity.get(), UsuarioResponse.class); + }else{ + return new ResponseEntity<>(usuarioResponse, HttpStatus.NOT_FOUND); + } + + return new ResponseEntity<>(usuarioResponse, HttpStatus.OK); + } + } \ No newline at end of file diff --git a/src/main/java/com/minsait/api/controller/ApiSwagger.java b/src/main/java/com/minsait/api/controller/ApiSwagger.java index 4eccc58..8180151 100644 --- a/src/main/java/com/minsait/api/controller/ApiSwagger.java +++ b/src/main/java/com/minsait/api/controller/ApiSwagger.java @@ -3,6 +3,9 @@ import com.minsait.api.controller.dto.ClienteRequest; import com.minsait.api.controller.dto.ClienteResponse; import com.minsait.api.controller.dto.MessageResponse; +import com.minsait.api.controller.dto.UsuarioRequest; +import com.minsait.api.controller.dto.UsuarioResponse; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; @@ -63,4 +66,56 @@ public interface ApiSwagger { } ) public ResponseEntity findById(Long id); + + @Operation(summary = "Busca todos os usuarios", + responses = { + @ApiResponse(responseCode = "200", description = "Dados do usuario retornados com sucesso"), + @ApiResponse(responseCode = "400", description = "Parâmetros inválidos"), + @ApiResponse(responseCode = "500", description = "Erro interno"), + @ApiResponse(responseCode = "403", description = "Acesso negado"), + } + ) + public ResponseEntity> usuarioFindAll(String nome, String login, String email, int page, int pagesize); + + @Operation(summary = "Insere um novo usuario", + responses = { + @ApiResponse(responseCode = "200", description = "Usuario inserido com sucesso"), + @ApiResponse(responseCode = "400", description = "Parâmetros inválidos"), + @ApiResponse(responseCode = "500", description = "Erro interno"), + @ApiResponse(responseCode = "403", description = "Acesso negado"), + } + ) + public ResponseEntity insertUsuario(UsuarioRequest request); + + @Operation(summary = "Atualiza um usuario", + responses = { + @ApiResponse(responseCode = "200", description = "Usuario atualizado com sucesso"), + @ApiResponse(responseCode = "400", description = "Parâmetros inválidos"), + @ApiResponse(responseCode = "500", description = "Erro interno"), + @ApiResponse(responseCode = "403", description = "Acesso negado"), + } + ) + public ResponseEntity updateUsuario(UsuarioRequest request); + + @Operation(summary = "Exclui um usuario", + responses = { + @ApiResponse(responseCode = "200", description = "Usuario excluído com sucesso"), + @ApiResponse(responseCode = "400", description = "Parâmetros inválidos"), + @ApiResponse(responseCode = "404", description = "Cliente não encontrado"), + @ApiResponse(responseCode = "500", description = "Erro interno"), + @ApiResponse(responseCode = "403", description = "Acesso negado"), + } + ) + public ResponseEntity deleteUsuario(Long id); + + @Operation(summary = "Busca um usuario pelo id", + responses = { + @ApiResponse(responseCode = "200", description = "Dados do cliente retornados com sucesso"), + @ApiResponse(responseCode = "400", description = "Parâmetros inválidos"), + @ApiResponse(responseCode = "404", description = "Cliente não encontrado"), + @ApiResponse(responseCode = "500", description = "Erro interno"), + @ApiResponse(responseCode = "403", description = "Acesso negado"), + } + ) + public ResponseEntity usuarioFindById(Long id); } diff --git a/src/main/java/com/minsait/api/controller/AuthController.java b/src/main/java/com/minsait/api/controller/AuthController.java index e2bff0f..752ef44 100644 --- a/src/main/java/com/minsait/api/controller/AuthController.java +++ b/src/main/java/com/minsait/api/controller/AuthController.java @@ -2,6 +2,8 @@ import com.minsait.api.controller.dto.GetTokenRequest; import com.minsait.api.controller.dto.GetTokenResponse; +import com.minsait.api.controller.dto.UsuarioRequest; +import com.minsait.api.repository.UsuarioEntity; import com.minsait.api.repository.UsuarioRepository; import com.minsait.api.sicurity.util.JWTUtil; import org.springframework.beans.factory.annotation.Autowired; @@ -17,6 +19,7 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.Optional; @RestController @RequestMapping(value = "/auth") @@ -30,17 +33,31 @@ public class AuthController { @PostMapping("/get-token") public ResponseEntity getToken(@RequestBody GetTokenRequest request){ - if(request.getPassword().equals("12345") && request.getUserName().equals("root")){ - final ArrayList permissions = new ArrayList<>(); - permissions.add("LEITURA_CLIENTE"); - permissions.add("ESCRITA_CLIENTE"); - - final var token =jwtUtil.generateToken("admin", permissions, 5); - return new ResponseEntity<>(GetTokenResponse.builder() - .accessToken(token) - .build(), HttpStatus.OK); - }else{ - return new ResponseEntity<>(GetTokenResponse.builder().build(), HttpStatus.UNAUTHORIZED); - } + BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); + + Optional usuarioEntity = Optional.ofNullable(usuarioRepository.findByLogin(request.getUserName())); + + if (usuarioEntity.isPresent()) { + UsuarioEntity usuario = usuarioEntity.get(); + boolean isIdenticalPassword = encoder.matches(request.getPassword(), usuario.getSenha()); + + if (isIdenticalPassword) { + int userId = Math.toIntExact(usuario.getId()); + String[] usuarioPermissions = usuario.getPermissoes().split(","); + ArrayList permissions = new ArrayList<>(List.of(usuarioPermissions)); + + String token = jwtUtil.generateToken(usuario.getLogin(), permissions, userId); + + GetTokenResponse response = GetTokenResponse.builder() + .accessToken(token) + .build(); + + return new ResponseEntity<>(response, HttpStatus.OK); + } else { + return new ResponseEntity<>(GetTokenResponse.builder().build(), HttpStatus.UNAUTHORIZED); + } + } else { + return new ResponseEntity<>(GetTokenResponse.builder().build(), HttpStatus.UNAUTHORIZED); + } } } diff --git a/src/main/java/com/minsait/api/repository/UsuarioEntity.java b/src/main/java/com/minsait/api/repository/UsuarioEntity.java index c6e2ada..e1361f3 100644 --- a/src/main/java/com/minsait/api/repository/UsuarioEntity.java +++ b/src/main/java/com/minsait/api/repository/UsuarioEntity.java @@ -37,4 +37,29 @@ public class UsuarioEntity { @Column(name = "PERMISSOES") private String permissoes; + + public Specification usuarioEntitySpecification() { + + return (root, query, criteriaBuilder) -> { + + List predicates = new ArrayList<>(); + + if (this.getNome() != null) { + predicates.add(criteriaBuilder.like(criteriaBuilder.lower(root.get("nome")), + "%" + this.getNome().trim().toLowerCase() + "%")); + } + + if (this.getNome() != null) { + predicates.add(criteriaBuilder.like(criteriaBuilder.lower(root.get("login")), + "%" + this.getNome().trim().toLowerCase() + "%")); + } + + if (this.getEmail() != null) { + predicates.add(criteriaBuilder.like(criteriaBuilder.lower(root.get("email")), + "%" + this.getEmail().trim().toLowerCase() + "%")); + } + + return criteriaBuilder.and(predicates.toArray(new Predicate[0])); + }; + } } diff --git a/src/main/java/com/minsait/api/sicurity/util/JWTUtil.java b/src/main/java/com/minsait/api/sicurity/util/JWTUtil.java index 55717c6..e6a208f 100644 --- a/src/main/java/com/minsait/api/sicurity/util/JWTUtil.java +++ b/src/main/java/com/minsait/api/sicurity/util/JWTUtil.java @@ -18,11 +18,11 @@ public class JWTUtil { @Value("${security.enabled}") private String securityEnabled; - public String generateToken(String username, ArrayList authorities, Integer user_id) { + public String generateToken(String username, ArrayList authorities, Integer i) { return Jwts.builder() .claim("user_name",username) .claim("authorities",authorities) - .claim("user_id", user_id) + .claim("user_id", i) .setExpiration(new Date(System.currentTimeMillis() + 600000)) .signWith(SignatureAlgorithm.HS512, this.jwtSecret.getBytes()) .compact(); diff --git a/src/main/resources/db/migration/V1_0__create_tables.sql b/src/main/resources/db/migration/V1_0__create_tables.sql index a13b393..bbb60e2 100644 --- a/src/main/resources/db/migration/V1_0__create_tables.sql +++ b/src/main/resources/db/migration/V1_0__create_tables.sql @@ -33,4 +33,7 @@ INSERT INTO API.CLIENTE (ID_CLIENTE, NOME, ENDERECO, EMAIL, TELEFONE) VALUES (AP INSERT INTO API.CLIENTE (ID_CLIENTE, NOME, ENDERECO, EMAIL, TELEFONE) VALUES (API.SQ_ID_CLIENTE.nextval,'Jão','Rua H, 343','jose14@outlook.com','53 988098432'); INSERT INTO API.CLIENTE (ID_CLIENTE, NOME, ENDERECO, EMAIL, TELEFONE) VALUES (API.SQ_ID_CLIENTE.nextval,'Manolo','Rua M, 342','jose14@outlook.com','53 98098234'); INSERT INTO API.CLIENTE (ID_CLIENTE, NOME, ENDERECO, EMAIL, TELEFONE) VALUES (API.SQ_ID_CLIENTE.nextval,'Wlisses','Rua N, 341','jose14@outlook.com','53 98098234'); -INSERT INTO API.CLIENTE (ID_CLIENTE, NOME, ENDERECO, EMAIL, TELEFONE) VALUES (API.SQ_ID_CLIENTE.nextval,'Leonardo','Rua O, 320','jose14@outlook.com','53 980928347'); \ No newline at end of file +INSERT INTO API.CLIENTE (ID_CLIENTE, NOME, ENDERECO, EMAIL, TELEFONE) VALUES (API.SQ_ID_CLIENTE.nextval,'Leonardo','Rua O, 320','jose14@outlook.com','53 980928347'); + +INSERT INTO API.USUARIO (ID_USUARIO, NOME, LOGIN, SENHA, EMAIL, PERMISSOES) VALUES (API.SQ_ID_USUARIO.nextval,'Root','root','$2a$10$YLB5vynNTFpphYxzjQPuruLmsdmoEcxSXO.3H.EVvrqXSKWptstUe', 'root@api.minsait.com', 'ESCRITA_CLIENTE,LEITURA_CLIENTE,ESCRITA_USUARIO,LEITURA_USUARIO'); +INSERT INTO API.USUARIO (ID_USUARIO, NOME, LOGIN, SENHA, EMAIL, PERMISSOES) VALUES (API.SQ_ID_USUARIO.nextval,'Administrador','admin','$2a$10$YLB5vynNTFpphYxzjQPuruLmsdmoEcxSXO.3H.EVvrqXSKWptstUe', 'admin@api.minsait.com', 'ESCRITA_CLIENTE,LEITURA_CLIENTE,ESCRITA_USUARIO,LEITURA_USUARIO'); \ No newline at end of file diff --git a/src/test/java/com/minsait/api/controller/UsuarioControllerTest.java b/src/test/java/com/minsait/api/controller/UsuarioControllerTest.java index b4aa2a2..a09f5c0 100644 --- a/src/test/java/com/minsait/api/controller/UsuarioControllerTest.java +++ b/src/test/java/com/minsait/api/controller/UsuarioControllerTest.java @@ -173,7 +173,7 @@ void updatePasword() throws Exception { final var usuarioAlterado = usuarioRepository.findByLogin(request.getLogin()); assertEquals(request.getNome(), usuarioAlterado.getNome()); - //verifica se a senha foi alerada no banco + //verifica se a senha foi alterada no banco BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); assertTrue(encoder.matches(request.getSenha(), usuarioAlterado.getSenha()));