Token's returns worked
This commit is contained in:
parent
ef8c2e8ca0
commit
dbf9d46679
11 changed files with 103 additions and 66 deletions
|
|
@ -23,10 +23,6 @@ configurations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.springframework.boot:spring-boot-starter'
|
implementation 'org.springframework.boot:spring-boot-starter'
|
||||||
compileOnly 'org.projectlombok:lombok'
|
compileOnly 'org.projectlombok:lombok'
|
||||||
|
|
@ -40,3 +36,7 @@ dependencies {
|
||||||
tasks.named('test') {
|
tasks.named('test') {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.withType(org.springframework.boot.gradle.tasks.aot.ProcessAot).configureEach {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
@ -3,46 +3,35 @@ package br.com.rayankonecny.authserviceapi.configs;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
|
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.SecurityFilterChain;
|
||||||
|
|
||||||
import static org.springframework.security.config.Customizer.withDefaults;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||||
|
|
||||||
http
|
http.authorizeHttpRequests(auth -> auth.requestMatchers("/auth/login", "/v3/api-docs/**", "/swagger-ui/**",
|
||||||
.authorizeHttpRequests(auth -> auth
|
"/swagger-ui.html", "/swagger-ui/index.html").permitAll().anyRequest().authenticated())
|
||||||
// AUTH
|
|
||||||
.requestMatchers("/auth/login").permitAll()
|
|
||||||
|
|
||||||
// SWAGGER / OPENAPI
|
// API pura → sem Basic
|
||||||
.requestMatchers(
|
.httpBasic(httpBasic -> httpBasic.disable())
|
||||||
"/v3/api-docs/**",
|
|
||||||
"/swagger-ui/**",
|
|
||||||
"/swagger-ui.html",
|
|
||||||
"/swagger-ui/index.html"
|
|
||||||
).permitAll()
|
|
||||||
|
|
||||||
// TODO o resto protegido
|
// Stateless (JWT)
|
||||||
.anyRequest().authenticated()
|
.csrf(csrf -> csrf.disable())
|
||||||
)
|
|
||||||
|
|
||||||
// API pura → sem Basic
|
// Sem sessão
|
||||||
.httpBasic(httpBasic -> httpBasic.disable())
|
.sessionManagement(session -> session.sessionCreationPolicy(
|
||||||
|
org.springframework.security.config.http.SessionCreationPolicy.STATELESS));
|
||||||
// Stateless (JWT)
|
|
||||||
.csrf(csrf -> csrf.disable())
|
|
||||||
|
|
||||||
// Sem sessão
|
|
||||||
.sessionManagement(session ->
|
|
||||||
session.sessionCreationPolicy(
|
|
||||||
org.springframework.security.config.http.SessionCreationPolicy.STATELESS
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PasswordEncoder passwordEncoder() {
|
||||||
|
return new BCryptPasswordEncoder();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,9 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import br.com.rayankonecny.hdcommoslib.models.exceptions.StandardError;
|
import br.com.rayankonecny.hdcommoslib.models.exceptions.StandardError;
|
||||||
import br.com.rayankonecny.hdcommoslib.models.requests.AuthenticateRequest;
|
import br.com.rayankonecny.hdcommoslib.models.requests.AuthenticateRequest;
|
||||||
import br.com.rayankonecny.hdcommoslib.models.responses.AuthenticationResponse;
|
import br.com.rayankonecny.hdcommoslib.models.responses.AuthenticationResponse;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.media.Content;
|
import io.swagger.v3.oas.annotations.media.Content;
|
||||||
import io.swagger.v3.oas.annotations.parameters.RequestBody;
|
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
import io.swagger.v3.oas.annotations.responses.ApiResponse;
|
||||||
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
import io.swagger.v3.oas.annotations.responses.ApiResponses;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
|
@ -17,7 +17,6 @@ import jakarta.validation.Valid;
|
||||||
|
|
||||||
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
|
||||||
|
|
||||||
|
|
||||||
@RequestMapping("/auth")
|
@RequestMapping("/auth")
|
||||||
public interface AuthController {
|
public interface AuthController {
|
||||||
|
|
||||||
|
|
@ -27,9 +26,10 @@ public interface AuthController {
|
||||||
@ApiResponse(responseCode = "400", description = "Bad request", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))),
|
@ApiResponse(responseCode = "400", description = "Bad request", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))),
|
||||||
@ApiResponse(responseCode = "401", description = "Bad credentials", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))),
|
@ApiResponse(responseCode = "401", description = "Bad credentials", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))),
|
||||||
@ApiResponse(responseCode = "404", description = "Username not found", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))),
|
@ApiResponse(responseCode = "404", description = "Username not found", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))),
|
||||||
@ApiResponse(responseCode = "500", description = "Internal server error", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))),
|
@ApiResponse(responseCode = "500", description = "Internal server error", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = StandardError.class))), })
|
||||||
})
|
|
||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
ResponseEntity<AuthenticationResponse> authenticate(@Valid @RequestBody final AuthenticateRequest requests) throws Exception;
|
ResponseEntity<AuthenticationResponse> authenticate(@RequestBody
|
||||||
|
@Valid
|
||||||
|
final AuthenticateRequest requests) throws Exception;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,26 @@
|
||||||
package br.com.rayankonecny.authserviceapi.controllers.impl;
|
package br.com.rayankonecny.authserviceapi.controllers.impl;
|
||||||
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import br.com.rayankonecny.authserviceapi.controllers.AuthController;
|
import br.com.rayankonecny.authserviceapi.controllers.AuthController;
|
||||||
import br.com.rayankonecny.authserviceapi.security.JWTAuthenticationImpl;
|
import br.com.rayankonecny.authserviceapi.services.AuthService;
|
||||||
import br.com.rayankonecny.authserviceapi.utils.JWTUtils;
|
|
||||||
import br.com.rayankonecny.hdcommoslib.models.requests.AuthenticateRequest;
|
import br.com.rayankonecny.hdcommoslib.models.requests.AuthenticateRequest;
|
||||||
import br.com.rayankonecny.hdcommoslib.models.responses.AuthenticationResponse;
|
import br.com.rayankonecny.hdcommoslib.models.responses.AuthenticationResponse;
|
||||||
|
import jakarta.validation.Valid;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class AuthControllerImpl implements AuthController {
|
public class AuthControllerImpl implements AuthController {
|
||||||
|
|
||||||
private final JWTUtils jwtUtils;
|
private final AuthService authService;
|
||||||
private final AuthenticationConfiguration authenticationConfiguration;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResponseEntity<AuthenticationResponse> authenticate(final AuthenticateRequest requests) throws Exception {
|
public ResponseEntity<AuthenticationResponse> authenticate(@Valid
|
||||||
return ResponseEntity.ok().body(
|
AuthenticateRequest request) {
|
||||||
new JWTAuthenticationImpl(jwtUtils, authenticationConfiguration.getAuthenticationManager()).authentication(requests));
|
|
||||||
|
return ResponseEntity.ok(authService.authenticate(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,21 @@ package br.com.rayankonecny.authserviceapi.models;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.data.annotation.Id;
|
||||||
|
import org.springframework.data.mongodb.core.mapping.Document;
|
||||||
|
|
||||||
import br.com.rayankonecny.hdcommoslib.models.enums.ProfileEnum;
|
import br.com.rayankonecny.hdcommoslib.models.enums.ProfileEnum;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
@NoArgsConstructor
|
||||||
|
@Document(collection = "user")
|
||||||
public class User {
|
public class User {
|
||||||
|
|
||||||
|
@Id
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
private String email;
|
private String email;
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,13 @@ import java.util.Collection;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Builder
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
public class UserDetailsDTO implements UserDetails {
|
public class UserDetailsDTO implements UserDetails {
|
||||||
|
|
||||||
@Serial
|
@Serial
|
||||||
|
|
@ -18,13 +20,13 @@ public class UserDetailsDTO implements UserDetails {
|
||||||
|
|
||||||
private String id;
|
private String id;
|
||||||
private String name;
|
private String name;
|
||||||
private String username;
|
private String email;
|
||||||
private String password;
|
private String password;
|
||||||
private Collection<? extends GrantedAuthority> authorities;
|
private Collection<? extends GrantedAuthority> authorities;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
public String getUsername() {
|
||||||
return this.authorities;
|
return this.email; // 🔥 FUNDAMENTAL
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -33,15 +35,10 @@ public class UserDetailsDTO implements UserDetails {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUsername() {
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
return this.username;
|
return this.authorities;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAccountNonExpired() {
|
public boolean isAccountNonExpired() {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -52,4 +49,13 @@ public class UserDetailsDTO implements UserDetails {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCredentialsNonExpired() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEnabled() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
package br.com.rayankonecny.authserviceapi.services;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
|
|
||||||
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import br.com.rayankonecny.authserviceapi.utils.JWTUtils;
|
||||||
|
import br.com.rayankonecny.hdcommoslib.models.requests.AuthenticateRequest;
|
||||||
|
import br.com.rayankonecny.hdcommoslib.models.responses.AuthenticationResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class AuthService {
|
||||||
|
|
||||||
|
private final UserDetailsServiceImpl userDetailsService;
|
||||||
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final JWTUtils jwtUtils;
|
||||||
|
|
||||||
|
public AuthenticationResponse authenticate(AuthenticateRequest request) {
|
||||||
|
|
||||||
|
var user = userDetailsService.loadUserByUsername(request.email());
|
||||||
|
|
||||||
|
if (!passwordEncoder.matches(request.password(), user.getPassword())) {
|
||||||
|
throw new BadCredentialsException("Invalid credentials");
|
||||||
|
}
|
||||||
|
|
||||||
|
String token = jwtUtils.generateToken(user);
|
||||||
|
|
||||||
|
return new AuthenticationResponse(token,user.getUsername());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package br.com.rayankonecny.authserviceapi.services;
|
||||||
|
|
||||||
|
public class BadCredentialsExceptionion {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
package br.com.rayankonecny.authserviceapi.services;
|
package br.com.rayankonecny.authserviceapi.services;
|
||||||
|
|
||||||
import java.util.stream.Collector;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
@ -20,7 +18,7 @@ public class UserDetailsServiceImpl implements UserDetailsService {
|
||||||
private final UserRepository repository;
|
private final UserRepository repository;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(final String email) throws UsernameNotFoundException {
|
public UserDetailsDTO loadUserByUsername(final String email) throws UsernameNotFoundException {
|
||||||
|
|
||||||
final var entity = repository.findByEmail(email)
|
final var entity = repository.findByEmail(email)
|
||||||
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + email));
|
.orElseThrow(() -> new UsernameNotFoundException("User not found: " + email));
|
||||||
|
|
@ -28,7 +26,7 @@ public class UserDetailsServiceImpl implements UserDetailsService {
|
||||||
return UserDetailsDTO.builder()
|
return UserDetailsDTO.builder()
|
||||||
.id(entity.getId())
|
.id(entity.getId())
|
||||||
.name(entity.getName())
|
.name(entity.getName())
|
||||||
.username(entity.getEmail())
|
.email(entity.getEmail())
|
||||||
.password(entity.getPassword())
|
.password(entity.getPassword())
|
||||||
.authorities(entity.getProfiles().stream().map(x -> new SimpleGrantedAuthority(x.getDescription())).collect(Collectors.toSet()))
|
.authorities(entity.getProfiles().stream().map(x -> new SimpleGrantedAuthority(x.getDescription())).collect(Collectors.toSet()))
|
||||||
.build();
|
.build();
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,12 @@ public class JWTUtils {
|
||||||
@Value("${jwt.expiration}")
|
@Value("${jwt.expiration}")
|
||||||
private Long expiration;
|
private Long expiration;
|
||||||
|
|
||||||
public String generateToken(final UserDetailsDTO dto) {
|
public String generateToken(final UserDetailsDTO user) {
|
||||||
return Jwts.builder()
|
return Jwts.builder()
|
||||||
.claim("id", dto.getId())
|
.claim("id", user.getId())
|
||||||
.claim("name", dto.getName())
|
.claim("name", user.getName())
|
||||||
.claim("authorities", dto.getAuthorities())
|
.claim("authorities", user.getAuthorities())
|
||||||
.setSubject(dto.getUsername())
|
.setSubject(user.getUsername())
|
||||||
.signWith(SignatureAlgorithm.HS512, secret.getBytes())
|
.signWith(SignatureAlgorithm.HS512, secret.getBytes())
|
||||||
.setExpiration(new Date(System.currentTimeMillis()+ expiration))
|
.setExpiration(new Date(System.currentTimeMillis()+ expiration))
|
||||||
.compact();
|
.compact();
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ spring:
|
||||||
mongodb:
|
mongodb:
|
||||||
uri: mongodb://175.15.15.6:27017/olympdb
|
uri: mongodb://175.15.15.6:27017/olympdb
|
||||||
auto-index-creation: true
|
auto-index-creation: true
|
||||||
|
aot:
|
||||||
|
enabled: false
|
||||||
jwt.secret: "IHf3Yua/byvtA+iIcGWmkrLvpKEXTb5ClkXaZ0VDmYbr/6b1otCs38x68bidvZLAOB7anUtVQlCid6YDULO5XA=="
|
jwt.secret: "IHf3Yua/byvtA+iIcGWmkrLvpKEXTb5ClkXaZ0VDmYbr/6b1otCs38x68bidvZLAOB7anUtVQlCid6YDULO5XA=="
|
||||||
jwt.expiration: 120000
|
jwt.expiration: 120000
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue