Skip to content

Commit

Permalink
Merge pull request #3 from GuilhermeDoSantoss/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
GuilhermeDoSantoss authored Jan 1, 2025
2 parents 32141bb + 8569455 commit 247670e
Show file tree
Hide file tree
Showing 11 changed files with 389 additions and 1 deletion.
17 changes: 16 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,26 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6'


compileOnly 'org.projectlombok:lombok'


runtimeOnly 'org.postgresql:postgresql'


annotationProcessor 'org.projectlombok:lombok'


testImplementation 'org.springframework.boot:spring-boot-starter-test'


testImplementation 'org.springframework.security:spring-security-test'


testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.guilherme.agendador_tarefas.infrastructure.enitity;
import jakarta.persistence.*;
import lombok.*;


@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Builder
@Table(name = "endereco")
public class Endereco {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "rua")
private String rua;
@Column(name = "numero")
private String numero;
@Column(name = "complemento", length = 10)
private String complemento;
@Column(name = "cidade", length = 150)
private String cidade;
@Column(name = "estado", length = 2)
private String estado;
@Column(name = "cep", length = 9)
private String cep;
@Column(name = "usuario_id")
private Long usuario_id;

public static Object biulder() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.guilherme.agendador_tarefas.infrastructure.enitity;
import jakarta.persistence.*;
import lombok.*;


@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Builder
@Table(name = "telefone")
public class Telefone {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "numero", length = 10)
private String numero;
@Column(name = "ddd", length = 5)
private String ddd;
@Column(name = "usuario_id")
private Long usuario_id;

public static Object biulder() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.guilherme.agendador_tarefas.infrastructure.enitity;
import jakarta.persistence.*;
import lombok.*;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;


@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Builder
@Table(name = "usuario")

public class Usuario implements UserDetails {

@Id
public Long id;
@Column(name = "nome", length = 100)
private String nome;
@Column (name = "email", length = 100)
private String email;
@Column(name = "senha")
private String senha;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "usuario_id", referencedColumnName = "id")
private List<Endereco> enderecos;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "usuario_id", referencedColumnName = "id")
private List<Telefone> telefones;


@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
}

@Override
public String getPassword() {
return senha;
}

@Override
public String getUsername() {
return email;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.guilherme.agendador_tarefas.infrastructure.repository;

import com.santos.firsy_spring_app.infrastructure.enitity.Endereco;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface EnderecoRepository extends JpaRepository<Endereco, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.guilherme.agendador_tarefas.infrastructure.repository;

import com.santos.firsy_spring_app.infrastructure.enitity.Telefone;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface TelefoneRepository extends JpaRepository<Telefone, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.guilherme.agendador_tarefas.infrastructure.repository;


import com.guilherme.agendador_tarefas.infrastructure.enitity.Usuario;
import jakarta.transaction.Transactional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

@Repository
public interface UsuarioRepository extends JpaRepository<Usuario, Long> {

boolean existsByEmail(String email);

Optional<Usuario> findByEmail(String email);

@Transactional
void deleteByEmail(String email);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package com.guilherme.agendador_tarefas.infrastructure.security;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

// Define a classe JwtRequestFilter, que estende OncePerRequestFilter
public class JwtRequestFilter extends OncePerRequestFilter {

// Define propriedades para armazenar instâncias de JwtUtil e UserDetailsService
private final JwtUtil jwtUtil;
private final UserDetailsService userDetailsService;

// Construtor que inicializa as propriedades com instâncias fornecidas
public JwtRequestFilter(JwtUtil jwtUtil, UserDetailsService userDetailsService) {
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}

// Metodo chamado uma vez por requisição para processar o filtro
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {

// Obtém o valor do header "Authorization" da requisição
final String authorizationHeader = request.getHeader("Authorization");

// Verifica se o header existe e começa com "Bearer "
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
// Extrai o token JWT do cabeçalho
final String token = authorizationHeader.substring(7);
// Extrai o nome de usuário do token JWT
final String username = jwtUtil.extrairEmailToken(token);

// Se o nome de usuário não for nulo e o usuário não estiver autenticado ainda
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
// Carrega os detalhes do usuário a partir do nome de usuário
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// Valida o token JWT
if (jwtUtil.validateToken(token, username)) {
// Cria um objeto de autenticação com as informações do usuário
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
// Define a autenticação no contexto de segurança
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}

// Continua a cadeia de filtros, permitindo que a requisição prossiga
chain.doFilter(request, response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.guilherme.agendador_tarefas.infrastructure.security;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.Date;

@Service
public class JwtUtil {

// Chave secreta usada para assinar e verificar tokens JWT
private final String secretKey = "sua-chave-secreta-super-segura-que-deve-ser-bem-longa";



// Gera um token JWT com o nome de usuário e validade de 1 hora
public String generateToken(String username) {
return Jwts.builder()
.setSubject(username) // Define o nome de usuário como o assunto do token
.setIssuedAt(new Date()) // Define a data e hora de emissão do token
.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60)) // Define a data e hora de expiração (1 hora a partir da emissão)
.signWith(Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8)), SignatureAlgorithm.HS256) // Converte a chave secreta em bytes e assina o token com ela
.compact(); // Constrói o token JWT
}

// Extrai as claims do token JWT (informações adicionais do token)
public Claims extractClaims(String token) {
return Jwts.parser()
.setSigningKey(Keys.hmacShaKeyFor(secretKey.getBytes(StandardCharsets.UTF_8))) // Define a chave secreta para validar a assinatura do token
.build()
.parseClaimsJws(token) // Analisa o token JWT e obtém as claims
.getBody(); // Retorna o corpo das claims
}

// Extrai o nome de usuário do token JWT
public String extrairEmailToken(String token) {
// Obtém o assunto (nome de usuário) das claims do token
return extractClaims(token).getSubject();
}

// Verifica se o token JWT está expirado
public boolean isTokenExpired(String token) {
// Compara a data de expiração do token com a data atual
return extractClaims(token).getExpiration().before(new Date());
}

// Valida o token JWT verificando o nome de usuário e se o token não está expirado
public boolean validateToken(String token, String username) {
// Extrai o nome de usuário do token
final String extractedUsername = extrairEmailToken(token);
// Verifica se o nome de usuário do token corresponde ao fornecido e se o token não está expirado
return (extractedUsername.equals(username) && !isTokenExpired(token));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.guilherme.agendador_tarefas.infrastructure.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

// Instâncias de JwtUtil e UserDetailsService injetadas pelo Spring
private final JwtUtil jwtUtil;
private final UserDetailsService userDetailsService;

// Construtor para injeção de dependências de JwtUtil e UserDetailsService
@Autowired
public SecurityConfig(JwtUtil jwtUtil, UserDetailsService userDetailsService) {
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}

// Configuração do filtro de segurança
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// Cria uma instância do JwtRequestFilter com JwtUtil e UserDetailsService
JwtRequestFilter jwtRequestFilter = new JwtRequestFilter(jwtUtil, userDetailsService);

http
.csrf(AbstractHttpConfigurer::disable) // Desativa proteção CSRF para APIs REST (não aplicável a APIs que não mantêm estado)
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/usuario/login").permitAll() // Permite acesso ao endpoint de login sem autenticação
.requestMatchers(HttpMethod.GET, "/auth").permitAll()// Permite acesso ao endpoint GET /auth sem autenticação
.requestMatchers(HttpMethod.POST, "/usuario").permitAll() // Permite acesso ao endpoint POST /usuario sem autenticação
.requestMatchers("/usuario/**").authenticated() // Requer autenticação para qualquer endpoint que comece com /usuario/
.anyRequest().authenticated() // Requer autenticação para todas as outras requisições
)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // Configura a política de sessão como stateless (sem sessão)
)
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class); // Adiciona o filtro JWT antes do filtro de autenticação padrão

// Retorna a configuração do filtro de segurança construída
return http.build();
}

// Configura o PasswordEncoder para criptografar senhas usando BCrypt
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // Retorna uma instância de BCryptPasswordEncoder
}

// Configura o AuthenticationManager usando AuthenticationConfiguration
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
// Obtém e retorna o AuthenticationManager da configuração de autenticação
return authenticationConfiguration.getAuthenticationManager();
}

}
Loading

0 comments on commit 247670e

Please sign in to comment.