Added tester React frontend, changed DTOs and User and UserRepository to fit around specialize USER key
This commit is contained in:
15
src/main/java/com/inoct/NoctuAuthenticator/JWTUtils.java
Normal file
15
src/main/java/com/inoct/NoctuAuthenticator/JWTUtils.java
Normal file
@@ -0,0 +1,15 @@
|
||||
package com.inoct.NoctuAuthenticator;
|
||||
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class JWTUtils {
|
||||
|
||||
public String generateToken(String username, String email, String source) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.inoct.NoctuAuthenticator.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.CorsConfigurationSource;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
//TODO Make sure it is rate-limited.
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
.requestMatchers("/login", "/register", "/oauth/**").permitAll() // Public authentication endpoints
|
||||
.anyRequest().authenticated() // Secure other endpoints
|
||||
)
|
||||
.csrf(csrf -> csrf.disable())
|
||||
.cors(cors -> cors.configurationSource(corsConfigurationSource())); // Enable CORS
|
||||
return http.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public CorsConfigurationSource corsConfigurationSource() {
|
||||
CorsConfiguration corsConfiguration = new CorsConfiguration();
|
||||
corsConfiguration.addAllowedOrigin("http://localhost:3000"); // Frontend URL
|
||||
corsConfiguration.addAllowedHeader("*"); // Allow all headers
|
||||
corsConfiguration.addAllowedMethod("*"); // Allow all HTTP methods
|
||||
corsConfiguration.setAllowCredentials(true); // Allow cookies/auth headers
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", corsConfiguration); // Apply to all endpoints
|
||||
return source;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BCryptPasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package com.inoct.NoctuAuthenticator.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import com.inoct.NoctuAuthenticator.dto.UserDTO;
|
||||
import com.inoct.NoctuAuthenticator.entity.User;
|
||||
import com.inoct.NoctuAuthenticator.service.UserService;
|
||||
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/")
|
||||
public class UserController {
|
||||
|
||||
@Autowired
|
||||
private UserService userService;
|
||||
|
||||
@GetMapping("/login")
|
||||
public ResponseEntity<UserDTO> loginUser(@RequestBody String username, @RequestBody String password) {
|
||||
UserDTO user = userService.authenticateUser(username, password);
|
||||
return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@GetMapping("/oauth")
|
||||
public ResponseEntity<UserDTO> oauthLogin(@RequestBody String username, @RequestBody String password) {
|
||||
UserDTO user = userService.authenticateUser(username, password);
|
||||
return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@PostMapping("/register")
|
||||
public ResponseEntity<User> registerUser(@RequestBody UserDTO userDTO) {
|
||||
System.out.println(userDTO);
|
||||
User user = userService.createUser(userDTO);
|
||||
return user != null ? ResponseEntity.ok(user) : ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<UserDTO> updateUser(@PathVariable Long id, @RequestBody User userDetails) {
|
||||
UserDTO updatedUser = userService.updateUser(id, userDetails);
|
||||
return updatedUser != null ? ResponseEntity.ok(updatedUser) : ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
|
||||
userService.deleteUser(id);
|
||||
return ResponseEntity.noContent().build();
|
||||
}
|
||||
|
||||
@GetMapping("/welcome")
|
||||
public String welcome(@AuthenticationPrincipal OAuth2User user) {
|
||||
Map<String, Object> attributes = user.getAttributes();
|
||||
return "Welcome " + attributes.get("name") + "!";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.inoct.NoctuAuthenticator.dto;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
|
||||
public class OauthDataDTO {
|
||||
private Long id;
|
||||
|
||||
private Long userId;
|
||||
|
||||
@NotNull
|
||||
private String provider;
|
||||
|
||||
@NotNull
|
||||
private String providerUserId;
|
||||
|
||||
@NotNull
|
||||
private String accessToken;
|
||||
|
||||
@NotNull
|
||||
private String refreshToken;
|
||||
|
||||
LocalDateTime expiresAt;
|
||||
|
||||
@NotNull
|
||||
private String [] scopes;
|
||||
}
|
||||
42
src/main/java/com/inoct/NoctuAuthenticator/dto/UserDTO.java
Normal file
42
src/main/java/com/inoct/NoctuAuthenticator/dto/UserDTO.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.inoct.NoctuAuthenticator.dto;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.inoct.NoctuAuthenticator.validation.ValidateUser;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Builder
|
||||
@ValidateUser
|
||||
public class UserDTO {
|
||||
private Long id;
|
||||
|
||||
@NotNull
|
||||
private String username;
|
||||
|
||||
@NotNull
|
||||
private String firstName;
|
||||
|
||||
@NotNull
|
||||
private String lastName;
|
||||
|
||||
private String email;
|
||||
|
||||
private List<String> roles;
|
||||
|
||||
private String password;
|
||||
|
||||
@NotNull
|
||||
private boolean oauth;
|
||||
|
||||
private OauthDataDTO oauthData;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.inoct.NoctuAuthenticator.entity;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
|
||||
@Entity
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||
@Builder
|
||||
public class OauthData {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@EqualsAndHashCode.Include
|
||||
private Long id;
|
||||
|
||||
@EqualsAndHashCode.Include
|
||||
@Transient
|
||||
private final UUID tempId = UUID.randomUUID();
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "user_id")
|
||||
@NotNull
|
||||
private User user;
|
||||
|
||||
@NotNull
|
||||
private String provider;
|
||||
|
||||
@NotNull
|
||||
private String providerUserId;
|
||||
|
||||
@NotNull
|
||||
private String accessToken;
|
||||
|
||||
@NotNull
|
||||
private String refreshToken;
|
||||
|
||||
LocalDateTime expiresAt;
|
||||
|
||||
@NotNull
|
||||
private String [] scopes;
|
||||
|
||||
@CreatedDate
|
||||
@Column(updatable = false)
|
||||
LocalDateTime createdDateTime;
|
||||
|
||||
@UpdateTimestamp
|
||||
LocalDateTime updateTimestamp;
|
||||
|
||||
}
|
||||
80
src/main/java/com/inoct/NoctuAuthenticator/entity/User.java
Normal file
80
src/main/java/com/inoct/NoctuAuthenticator/entity/User.java
Normal file
@@ -0,0 +1,80 @@
|
||||
package com.inoct.NoctuAuthenticator.entity;
|
||||
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
import org.hibernate.validator.constraints.UniqueElements;
|
||||
import org.springframework.data.annotation.CreatedDate;
|
||||
|
||||
import com.inoct.NoctuAuthenticator.validation.ValidateUser;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.EqualsAndHashCode.Include;
|
||||
|
||||
|
||||
|
||||
@Entity
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
@Setter
|
||||
@ValidateUser
|
||||
@Table(name = "users",
|
||||
uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = "username"),
|
||||
@UniqueConstraint(columnNames = "email")
|
||||
})
|
||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
|
||||
public class User {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Include
|
||||
private Long id;
|
||||
|
||||
@Include
|
||||
@NotNull
|
||||
private String username;
|
||||
|
||||
@Transient
|
||||
@Include
|
||||
private final UUID tempId = UUID.randomUUID();
|
||||
|
||||
@NotNull
|
||||
private String firstName;
|
||||
@NotNull
|
||||
private String lastName;
|
||||
|
||||
@Include
|
||||
private String email;
|
||||
|
||||
private String password;
|
||||
|
||||
private List<String> roles;
|
||||
|
||||
@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
|
||||
OauthData oauthData;
|
||||
|
||||
@NotNull
|
||||
private boolean oauth;
|
||||
|
||||
@CreatedDate
|
||||
@Column(updatable = false)
|
||||
private LocalDate createdDate;
|
||||
|
||||
@UpdateTimestamp
|
||||
private LocalDate updatedDate;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.inoct.NoctuAuthenticator.repository;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import com.inoct.NoctuAuthenticator.entity.User;
|
||||
|
||||
@Repository
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
User findByUsername(String username);
|
||||
User findByEmail(String email);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.inoct.NoctuAuthenticator.service;
|
||||
|
||||
import com.inoct.NoctuAuthenticator.dto.UserDTO;
|
||||
import com.inoct.NoctuAuthenticator.entity.User;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public interface UserService {
|
||||
|
||||
List<UserDTO> findAllUsers();
|
||||
|
||||
UserDTO authenticateUser(String userName, String password);
|
||||
|
||||
UserDTO getUserById(Long id);
|
||||
|
||||
User createUser(UserDTO user);
|
||||
|
||||
void deleteUser(Long id);
|
||||
|
||||
UserDTO findUserByUsername(String username);
|
||||
|
||||
UserDTO findUserByEmail(String email);
|
||||
|
||||
UserDTO updateUser(Long id, User userDetails);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package com.inoct.NoctuAuthenticator.service.impl;
|
||||
|
||||
import com.inoct.NoctuAuthenticator.dto.UserDTO;
|
||||
import com.inoct.NoctuAuthenticator.entity.User;
|
||||
import com.inoct.NoctuAuthenticator.repository.UserRepository;
|
||||
import com.inoct.NoctuAuthenticator.service.UserService;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class UserServiceImpl implements UserService {
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public User createUser(UserDTO userDTO) {
|
||||
User user = mapFromDTO(userDTO);
|
||||
return userRepository.save(user);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteUser(Long id) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UserDTO> findAllUsers() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDTO findUserByEmail(String email) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDTO getUserById(Long id) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDTO findUserByUsername(String username) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDTO updateUser(Long id, User userDetails) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDTO authenticateUser(String userName, String password) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
private UserDTO mapToDTO(User user) {
|
||||
UserDTO userDTO = UserDTO.builder()
|
||||
.id(user.getId())
|
||||
.username(user.getUsername())
|
||||
.firstName(user.getFirstName())
|
||||
.lastName(user.getLastName())
|
||||
.email(user.getEmail())
|
||||
.roles(user.getRoles())
|
||||
.oauth(user.isOauth())
|
||||
.build();
|
||||
return userDTO;
|
||||
}
|
||||
|
||||
private User mapFromDTO(UserDTO userDTO) {
|
||||
User user = User.builder()
|
||||
.username(userDTO.getUsername())
|
||||
.firstName(userDTO.getFirstName())
|
||||
.lastName(userDTO.getLastName())
|
||||
.email(userDTO.getEmail())
|
||||
.roles(userDTO.getRoles())
|
||||
.oauth(userDTO.isOauth())
|
||||
.build();
|
||||
return user;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.inoct.NoctuAuthenticator.validation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
|
||||
@Constraint(validatedBy = ValidateUserValidator.class)
|
||||
@Target({ElementType.TYPE}) // Apply this annotation at the class level
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ValidateUser {
|
||||
String message() default "Invalid user details";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.inoct.NoctuAuthenticator.validation;
|
||||
|
||||
import com.inoct.NoctuAuthenticator.entity.User;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
public class ValidateUserValidator implements ConstraintValidator<ValidateUser, User> {
|
||||
|
||||
@Override
|
||||
public boolean isValid(User user, ConstraintValidatorContext context) {
|
||||
if (user == null) {
|
||||
return true; // Validation for null objects is handled separately
|
||||
}
|
||||
|
||||
// Example validation logic:
|
||||
// Ensure the username is not null and at least 3 characters long
|
||||
if (user.getUsername() == null || user.getUsername().length() < 3) {
|
||||
context.buildConstraintViolationWithTemplate("Username must be at least 3 characters long")
|
||||
.addPropertyNode("username")
|
||||
.addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ensure the email follows a specific pattern (simplified example)
|
||||
if (user.getEmail() != null && !user.getEmail().contains("@")) {
|
||||
context.buildConstraintViolationWithTemplate("Invalid email format")
|
||||
.addPropertyNode("email")
|
||||
.addConstraintViolation();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true; // Valid user
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,28 @@ spring.datasource.username=${POSTGRES_USER}
|
||||
spring.datasource.password=${POSTGRES_PASSWORD}
|
||||
spring.datasource.driver-class-name=org.postgresql.Driver
|
||||
|
||||
|
||||
#JPA configuration
|
||||
sprint.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
|
||||
spring.jpa.hibernate.ddl-auto=create-drop
|
||||
|
||||
|
||||
# Redis configuration
|
||||
spring.redis.host=${REDIS_HOST}
|
||||
spring.redis.port=${REDIS_PORT}
|
||||
#spring.redis.password=${REDIS_PASSWORD}
|
||||
|
||||
#Google Oauth2.0 configuration
|
||||
# OAuth2 Client Configuration for Google
|
||||
spring.security.oauth2.client.registration.google.client-id=${GOOGLE_CLIENT_ID}
|
||||
spring.security.oauth2.client.registration.google.client-secret=${GOOGLE_CLIENT_SECRET}
|
||||
spring.security.oauth2.client.registration.google.redirect-uri=http://localhost:8080/login/oauth2/code/google
|
||||
spring.security.oauth2.client.registration.google.scope=email,profile
|
||||
spring.security.oauth2.client.registration.google.client-authentication-method=post
|
||||
spring.security.oauth2.client.registration.google.authorization-grant-type=authorization_code
|
||||
|
||||
# Provider-specific configuration (optional)
|
||||
spring.security.oauth2.client.provider.google.authorization-uri=https://accounts.google.com/o/oauth2/v2/auth
|
||||
spring.security.oauth2.client.provider.google.token-uri=https://oauth2.googleapis.com/token
|
||||
spring.security.oauth2.client.provider.google.user-info-uri=https://openidconnect.googleapis.com/v1/userinfo
|
||||
spring.security.oauth2.client.provider.google.user-name-attribute=sub
|
||||
|
||||
Reference in New Issue
Block a user