From 0322c54e42e21bd8748af149a2cfc522e92bff96 Mon Sep 17 00:00:00 2001 From: toximu Date: Tue, 3 Mar 2026 20:56:09 +0300 Subject: [PATCH 01/11] create Authentication service --- AuthService/.gitattributes | 3 + AuthService/.gitignore | 37 +++++++ AuthService/build.gradle | 36 +++++++ AuthService/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 46175 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 ++ AuthService/settings.gradle | 1 + .../AdminController/AdminController.java | 14 +++ .../AuthController/AuthController.java | 92 ++++++++++++++++++ .../authservice/AuthServiceApplication.java | 13 +++ .../JWTRequestFilter/JWTRequestFilter.java | 64 ++++++++++++ .../authservice/JWTUtils/JWTUtils.java | 52 ++++++++++ .../SimpleController/SimpleController.java | 15 +++ .../ViewController/ViewController.java | 18 ++++ .../authservice/config/PasswordConfig.java | 15 +++ .../authservice/config/SecurityConfig.java | 55 +++++++++++ .../authservice/config/UserConfig.java | 20 ++++ .../src/main/resources/application.properties | 1 + .../src/main/resources/static/login.html | 81 +++++++++++++++ .../src/main/resources/static/signup.html | 69 +++++++++++++ .../AuthServiceApplicationTests.java | 13 +++ 20 files changed, 606 insertions(+) create mode 100644 AuthService/.gitattributes create mode 100644 AuthService/.gitignore create mode 100644 AuthService/build.gradle create mode 100644 AuthService/gradle/wrapper/gradle-wrapper.jar create mode 100644 AuthService/gradle/wrapper/gradle-wrapper.properties create mode 100644 AuthService/settings.gradle create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/AuthServiceApplication.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/config/PasswordConfig.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/config/UserConfig.java create mode 100644 AuthService/src/main/resources/application.properties create mode 100644 AuthService/src/main/resources/static/login.html create mode 100644 AuthService/src/main/resources/static/signup.html create mode 100644 AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java diff --git a/AuthService/.gitattributes b/AuthService/.gitattributes new file mode 100644 index 0000000..8af972c --- /dev/null +++ b/AuthService/.gitattributes @@ -0,0 +1,3 @@ +/gradlew text eol=lf +*.bat text eol=crlf +*.jar binary diff --git a/AuthService/.gitignore b/AuthService/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/AuthService/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/AuthService/build.gradle b/AuthService/build.gradle new file mode 100644 index 0000000..1b5acec --- /dev/null +++ b/AuthService/build.gradle @@ -0,0 +1,36 @@ +plugins { + id 'java' + id 'org.springframework.boot' version '4.0.3' + id 'io.spring.dependency-management' version '1.1.7' +} + +group = 'codzilla.backend' +version = '0.0.1-SNAPSHOT' +description = 'AuthService' + +java { + toolchain { + languageVersion = JavaLanguageVersion.of(23) + } +} + +repositories { + mavenCentral() +} + +dependencies { + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-webmvc' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + testImplementation 'org.springframework.boot:spring-boot-starter-security-test' + testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test' + testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'io.jsonwebtoken:jjwt-api:0.12.5' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' + runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' +} + +tasks.named('test') { + useJUnitPlatform() +} diff --git a/AuthService/gradle/wrapper/gradle-wrapper.jar b/AuthService/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..61285a659d17295f1de7c53e24fdf13ad755c379 GIT binary patch literal 46175 zcma&NWmKG9wk?cn;qLD4?(Xgo+}#P9AcecTOK=k0-KB7X7w!%r36RU%ea89j>2v%2 zy2jY`r|L&NwdbC5&AHZASAvGYhCo0-fPjFYcwhhD3mpOxLPbVff<-}9mQ7hfN=8*n zMn@YK0`jk~Y#ADPZt&s;&o%Vh+1OqX$SQPQUbO~kT2|`trE{h9WQ$5t)0<0SGK(9o zy!{fv+oYdReexE`UMYzV3-kOr>x=rJ7+6+0b5EnF$IG$Dt(hUAKx2>*-_*>j|Id49Q3}YN>5=$q?@D;}*%{N1&Ngq- zT;Qj#_R=+0ba4EqMNa487mOM?^?N!cyt;9!ID^&OIS$OX?qC^kSGrHw@&-mB@~L!$ zQMIB|qD849?j6c_o6Y9s2-@J%jl@tu1+mdGN~J$RK!v{juhQkNSMup%E!|Iwjp}G} z6l3PDwQp#b$A`v-92bY=W{dghjg1@gO53Q}P!4oN?n)(dY4}3I1erK<3&=O2;)*)+_&gzJwCFLYl&;nZCm zs21P5net@>H0V>H2FQ%TUoZBiSRH2w*u~K%d6Y|Fc_eO}lhQ1A!Z|)oX3+mS``s4O zQE>^#ibNrUi4P;{KRbbTOVweOhejS2x&Oab?s zB}^!pSukn*hb<|^*8b+28w~Kqr z5YDH20(#-gOLJR&1Q4qEEb{G)%nsAqPsEfj9FgZ% z5k%IHRQk6Xh}==R`LYmK?%(0w9zI}hkkj|3qvo$_FzU9$%Zf>(S>m|JTn!rYUwC)S z^+V+Gh@*U(Za&jUW#Wh#;1*R2he9SI68(&DeI%UQ&0gyQ73g7)Xts{uPx^&U`MALc)G9+Y<9KIjR1lICfNnw_Ju8 z-O7hoBM!+}IMUYZr29cN{aHL&dmr!ayq7;r?`7M3z+L@~Fx4o}lk{l?0w3=rqRxpv z0Tp-ETUvB<*2vTh_dr%}Lfx)%pxlb$ch}yCCUz6k4)hyMJ_Lq$SS(Rd8aWG-K{8TD zDUtTM2SQ|y5F;}M&9eL-xGpj#vTy0*Egq$K1aZnGq3I^$31WARgcJUb0T*QaRo~*Q*;H_Jc_7LeyDXHPh?}Ick1s{(QZWni3%OL|i zJ7foQ%gLbU+dOZP7Z^96OoW5YbS=0%+#j3#o3bYsnB}Ztbu_KuFcBz9M~>z z{s?I|KWR0CJT6eqNlIj57Jq@-><8 zV&>W=5}GL`X|of9PiXwZaoKWOehcgaB1!y0@zY^+$YFgk3UB@$4#qATzJk?b^M#iL zKe}&w?|SGj<-3Z>pDd^+G3w_>76zq%EZGhqzOYx6YQgnb;vA^%6(Sx4?gytM=^m`C z@c+mG0LSQOqF$oK!j8-B4hG`=`%8Hp#$+IvanscDc42T#q4=v2YuoSZd{VS%kBNtx zLd6U%s>y+0*0?dDt&wJ`=F&iRWyJS1Y>kZds97Z^J?Kmeu!Fh-L+F9?o#ZILhhvI& zyE^o10y()W>x@1skNd<(ehL$G%S9yZ>AxGNktZ_$h9RD?hd_YxvNIeb?3~*XE*54b z;}9`U&d_XFzBbijUqrX}i?s24Ox?EOfTz$aTz;dtw~F)!(XK9voHS_ii|YmI?eRrX z%Gr=T-7Qx7eB&|iMk+jCw4x6X6Hae`0esw}b;uVy6ljeACOq{ZM6e`2k%XdE* zcZotR`H{lmO?;6sfMz|Xv|aJ!F2{Ucp1Y5HM68;}hw4h%ntF`pl0QNFk@W?2S67+W zF1AU5YS7<_7H6+NrwMJ)&D8^-Sgj_rttU*gt3dvWH^sG8W6BbhtT{Lm3VV5cSo;$3 zNuSXq<>-4y>$9__aC`0aka&~k=}#N;Co3O<6()7bWgAZuB~%E!lv`DCbEMM)G$IQ< z*b89{3RV{((?H&X1kBl8+K_XHL`Hc=25|M6Djk8YZUc&s3Ki&|KcOb&!$LVf5~6*K z>pgW7g-7ASM5ZZ5?Ah_e13r7Z98K>?leVWPNQs_MXx_&Ftg92|SR`xrt$4|%fVGS- zTNZt(a#pl7RaYzzJlX1vk0kt*Vpxw_{M%KG%Q}`scIVU

pVX@HRij*jw$g4?}Pn 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 literal 0 HcmV?d00001 diff --git a/AuthService/gradle/wrapper/gradle-wrapper.properties b/AuthService/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37f78a6 --- /dev/null +++ b/AuthService/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/AuthService/settings.gradle b/AuthService/settings.gradle new file mode 100644 index 0000000..15ac831 --- /dev/null +++ b/AuthService/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'AuthService' diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java b/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java new file mode 100644 index 0000000..dba046b --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java @@ -0,0 +1,14 @@ +package codzilla.backend.authservice.AdminController; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/admin") +public class AdminController { + @GetMapping("/") + String getAdminInfo() { + return "Some admin info."; + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java b/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java new file mode 100644 index 0000000..6407263 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java @@ -0,0 +1,92 @@ +package codzilla.backend.authservice.AuthController; + +import codzilla.backend.authservice.JWTUtils.JWTUtils; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.web.bind.annotation.*; + +@Slf4j +@RestController +@RequestMapping("/auth") +public class AuthController { + private final AuthenticationManager authManager; + private final InMemoryUserDetailsManager manager; + private final PasswordEncoder encoder; + + @Autowired + public AuthController(AuthenticationManager authManager, InMemoryUserDetailsManager manager, PasswordEncoder encoder) { + this.manager = manager; + this.encoder = encoder; + this.authManager = authManager; + } + + @PostMapping("/login") + public ResponseEntity login(@RequestBody LoginRequest req, HttpServletResponse response) { + log.info("Auth user by password..."); + Authentication auth = authManager.authenticate( + new UsernamePasswordAuthenticationToken(req.username, req.password) + ); + + var token = JWTUtils.generateToken(auth); + + Cookie cookie = new Cookie("jwt", token); + cookie.setHttpOnly(true); + cookie.setSecure(false); + cookie.setPath("/"); + cookie.setMaxAge(60 * 60); + response.addCookie(cookie); + + + UserDetails user = (UserDetails) auth.getPrincipal(); + return ResponseEntity.ok("You are logged in! Your roles are " + user.getAuthorities().toString() + "."); + } + + @PostMapping("/logout") + public ResponseEntity logout(HttpServletResponse response) { + Cookie cookie = new Cookie("jwt", null); + cookie.setPath("/"); + cookie.setHttpOnly(true); + cookie.setMaxAge(0); + + response.addCookie(cookie); + + return ResponseEntity.ok("Logged out successfully"); + } + + + @PostMapping("/signup") + public ResponseEntity signUp(@RequestBody SignupRequest request) { + + UserDetails userDetails = User. + withUsername(request.username). + password(encoder.encode(request.password)). + roles("USER").build(); + manager.createUser(userDetails); + + return ResponseEntity.ok("User created!"); + } + +} + +class LoginRequest { + public String username; + public String password; +} + +class SignupRequest { + public String username; + public String password; +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AuthServiceApplication.java b/AuthService/src/main/java/codzilla/backend/authservice/AuthServiceApplication.java new file mode 100644 index 0000000..bed022d --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/AuthServiceApplication.java @@ -0,0 +1,13 @@ +package codzilla.backend.authservice; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class AuthServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(AuthServiceApplication.class, args); + } + +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java b/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java new file mode 100644 index 0000000..6aaafc0 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java @@ -0,0 +1,64 @@ +package codzilla.backend.authservice.JWTRequestFilter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; +import java.util.List; + +import codzilla.backend.authservice.JWTUtils.JWTUtils; + +@Slf4j +@Component +public class JWTRequestFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + log.info("In filter."); + String token = null; + if (request.getCookies() != null) { + for (var cookie : request.getCookies()) { + if ("jwt".equals(cookie.getName())) { + token = cookie.getValue(); + break; + } + } + } + if (token != null) { + + log.info("Got token."); + try { + String username = JWTUtils.getUsernameFromToken(token); + List roles = JWTUtils.getRolesFromToken(token); + log.info("{} has jwt. His roles: {}", username, roles); + + List authorities = roles.stream() + .map(SimpleGrantedAuthority::new) + .toList(); + + + UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken( + username, + null, + authorities + ); + + + SecurityContextHolder.getContext().setAuthentication(auth); + } catch (Exception e) { + log.error("dont auth user"); + } + } + + filterChain.doFilter(request, response); + + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java b/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java new file mode 100644 index 0000000..d242006 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java @@ -0,0 +1,52 @@ +package codzilla.backend.authservice.JWTUtils; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.User; +import org.springframework.stereotype.Component; + +import javax.crypto.SecretKey; +import java.util.Date; +import java.util.List; + +@Component +public class JWTUtils { + + private static SecretKey secret = Jwts.SIG.HS256.key().build(); + + public static String generateToken(Authentication authentication) { + List roles = authentication.getAuthorities().stream() + .map(GrantedAuthority::getAuthority) + .toList(); + + return Jwts.builder() + .subject(authentication.getName()) + .claim("roles", roles) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + 86400000)) + .signWith(secret) + .compact(); + } + + public static List getRolesFromToken(String token) { + Claims claims = Jwts.parser() + .verifyWith(secret) + .build() + .parseSignedClaims(token) + .getPayload(); + + return claims.get("roles", List.class); + } + + public static String getUsernameFromToken(String token) { + return Jwts.parser() + .verifyWith(secret) + .build() + .parseSignedClaims(token) + .getPayload() + .getSubject(); + } +} + diff --git a/AuthService/src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java b/AuthService/src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java new file mode 100644 index 0000000..62f9874 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java @@ -0,0 +1,15 @@ +package codzilla.backend.authservice.SimpleController; + + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/simple") +public class SimpleController { + @GetMapping("/") + String getSomeInfo() { + return "Some common info."; + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java b/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java new file mode 100644 index 0000000..617f7ea --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java @@ -0,0 +1,18 @@ +package codzilla.backend.authservice.ViewController; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; + +@Controller +public class ViewController { + @GetMapping("/login") + public String getLoginPage() { + return "login.html"; + } + + @GetMapping("/signup") + public String getSignUpPage() { + return "signup.html"; + } +} + diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/PasswordConfig.java b/AuthService/src/main/java/codzilla/backend/authservice/config/PasswordConfig.java new file mode 100644 index 0000000..ed1e5c4 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/config/PasswordConfig.java @@ -0,0 +1,15 @@ +package codzilla.backend.authservice.config; + + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; + +@Configuration +public class PasswordConfig { + + @Bean + public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } + +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java b/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java new file mode 100644 index 0000000..4d49c9a --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java @@ -0,0 +1,55 @@ +package codzilla.backend.authservice.config; + +import codzilla.backend.authservice.JWTRequestFilter.JWTRequestFilter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.CorsConfigurationSource; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; + +import java.util.Arrays; + +@Configuration +@EnableMethodSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http, JWTRequestFilter filter) throws Exception { + return http + .csrf(csrf -> csrf.disable()) + .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/auth/login", "/login", "/login.html", "/auth/logout", "/auth/signup", "/signup", "/signup.html").permitAll() + .requestMatchers("/admin/**").hasRole("ADMIN") + .anyRequest().authenticated() + ) + .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class) + .build(); + + } + + @Bean + public AuthenticationManager authManager(AuthenticationConfiguration config) throws Exception { + return config.getAuthenticationManager(); + } + + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration configuration = new CorsConfiguration(); + configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); // Твой фронт + configuration.setAllowCredentials(true); // РАЗРЕШАЕМ КУКИ + configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); + configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); + + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", configuration); + return source; + } +} \ No newline at end of file diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/UserConfig.java b/AuthService/src/main/java/codzilla/backend/authservice/config/UserConfig.java new file mode 100644 index 0000000..c7d64e0 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/config/UserConfig.java @@ -0,0 +1,20 @@ +package codzilla.backend.authservice.config; + + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; + +@Configuration +public class UserConfig { + + @Bean + public InMemoryUserDetailsManager inMemoryUserDetailsManager(PasswordEncoder encoder) { + return new InMemoryUserDetailsManager( + User.withUsername("admin").password(encoder.encode("admin")).roles("ADMIN").build(), + User.withUsername("user").password(encoder.encode("user")).roles("USER").build() + ); + } +} diff --git a/AuthService/src/main/resources/application.properties b/AuthService/src/main/resources/application.properties new file mode 100644 index 0000000..619f739 --- /dev/null +++ b/AuthService/src/main/resources/application.properties @@ -0,0 +1 @@ +spring.application.name=AuthService \ No newline at end of file diff --git a/AuthService/src/main/resources/static/login.html b/AuthService/src/main/resources/static/login.html new file mode 100644 index 0000000..dcad533 --- /dev/null +++ b/AuthService/src/main/resources/static/login.html @@ -0,0 +1,81 @@ + + + + + Login + + + +

+ + + + \ No newline at end of file diff --git a/AuthService/src/main/resources/static/signup.html b/AuthService/src/main/resources/static/signup.html new file mode 100644 index 0000000..c791cf7 --- /dev/null +++ b/AuthService/src/main/resources/static/signup.html @@ -0,0 +1,69 @@ + + + + + Регистрация + + + + +
+

Создать аккаунт

+ + + + +

+

Уже есть аккаунт? Войти

+
+ + + + + \ No newline at end of file diff --git a/AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java b/AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java new file mode 100644 index 0000000..c66d2bd --- /dev/null +++ b/AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java @@ -0,0 +1,13 @@ +package codzilla.backend.authservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class AuthServiceApplicationTests { + + @Test + void contextLoads() { + } + +} From 094bd3796f45ce9cb5bd3f8de855fcd53fc1c930 Mon Sep 17 00:00:00 2001 From: toximu Date: Wed, 4 Mar 2026 23:39:03 +0300 Subject: [PATCH 02/11] implement refresh JWT tokens --- AuthService/build.gradle | 1 + AuthService/gradlew | 248 ++++++++++++++++++ AuthService/gradlew.bat | 93 +++++++ .../AuthController/AuthController.java | 76 +++++- .../JWTRequestFilter/JWTRequestFilter.java | 10 +- .../authservice/JWTUtils/JWTUtils.java | 43 ++- .../ViewController/ViewController.java | 5 + .../authservice/config/RedisConfig.java | 26 ++ .../authservice/config/SecurityConfig.java | 11 +- .../backend/authservice/config/Settings.java | 16 ++ .../src/main/resources/application.properties | 4 +- 11 files changed, 507 insertions(+), 26 deletions(-) create mode 100755 AuthService/gradlew create mode 100644 AuthService/gradlew.bat create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/config/RedisConfig.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/config/Settings.java diff --git a/AuthService/build.gradle b/AuthService/build.gradle index 1b5acec..830cbb0 100644 --- a/AuthService/build.gradle +++ b/AuthService/build.gradle @@ -21,6 +21,7 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-webmvc' + implementation('org.springframework.boot:spring-boot-starter-data-redis') compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-security-test' diff --git a/AuthService/gradlew b/AuthService/gradlew new file mode 100755 index 0000000..adff685 --- /dev/null +++ b/AuthService/gradlew @@ -0,0 +1,248 @@ +#!/bin/sh + +# +# Copyright © 2015 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/AuthService/gradlew.bat b/AuthService/gradlew.bat new file mode 100644 index 0000000..c4bdd3a --- /dev/null +++ b/AuthService/gradlew.bat @@ -0,0 +1,93 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java b/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java index 6407263..811926a 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java @@ -1,17 +1,17 @@ package codzilla.backend.authservice.AuthController; import codzilla.backend.authservice.JWTUtils.JWTUtils; +import codzilla.backend.authservice.config.Settings; import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; @@ -25,12 +25,17 @@ public class AuthController { private final AuthenticationManager authManager; private final InMemoryUserDetailsManager manager; private final PasswordEncoder encoder; + private final JWTUtils jwtUtils; + private final Settings settings; @Autowired - public AuthController(AuthenticationManager authManager, InMemoryUserDetailsManager manager, PasswordEncoder encoder) { + public AuthController(AuthenticationManager authManager, InMemoryUserDetailsManager manager, PasswordEncoder encoder, + JWTUtils jwtUtils, Settings settings) { this.manager = manager; this.encoder = encoder; this.authManager = authManager; + this.jwtUtils = jwtUtils; + this.settings = settings; } @PostMapping("/login") @@ -40,15 +45,21 @@ public ResponseEntity login(@RequestBody LoginRequest req, HttpServletRespons new UsernamePasswordAuthenticationToken(req.username, req.password) ); - var token = JWTUtils.generateToken(auth); - - Cookie cookie = new Cookie("jwt", token); - cookie.setHttpOnly(true); - cookie.setSecure(false); - cookie.setPath("/"); - cookie.setMaxAge(60 * 60); - response.addCookie(cookie); - + var accessToken = jwtUtils.generateAccessToken(auth); + Cookie jwtCookie = new Cookie("jwt", accessToken); + jwtCookie.setHttpOnly(true); + jwtCookie.setSecure(false); + jwtCookie.setPath("/"); + jwtCookie.setMaxAge(/*(int) settings.getRefreshTokenTtl().toSeconds()*/ 3600); + response.addCookie(jwtCookie); + + var refreshToken = jwtUtils.generateRefreshToken(auth); + Cookie refreshCookie = new Cookie("refresh_jwt", refreshToken); + refreshCookie.setPath("/"); + refreshCookie.setHttpOnly(true); + refreshCookie.setMaxAge(/*(int) settings.getRefreshTokenTtl().toSeconds()*/ 3600); + refreshCookie.setSecure(false); + response.addCookie(refreshCookie); UserDetails user = (UserDetails) auth.getPrincipal(); return ResponseEntity.ok("You are logged in! Your roles are " + user.getAuthorities().toString() + "."); @@ -79,6 +90,45 @@ public ResponseEntity signUp(@RequestBody SignupRequest request) { return ResponseEntity.ok("User created!"); } + @PostMapping("/refresh") + public ResponseEntity refreshToken(HttpServletRequest request, HttpServletResponse response) { + String refreshToken = null; + if (request.getCookies() != null) { + for (var cookie : request.getCookies()) { + if ("refresh_jwt".equals(cookie.getName())) { + refreshToken = cookie.getValue(); + break; + } + } + + if (refreshToken == null) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("No token in cookie."); + if (!jwtUtils.validateToken(refreshToken)) + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Token is wrong."); + + String username = jwtUtils.getUsernameFromToken(refreshToken); + + UserDetails userDetails = manager.loadUserByUsername(username); + + UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken( + userDetails, + null, + userDetails.getAuthorities() + ); + + var accessToken = jwtUtils.generateAccessToken(auth); + Cookie cookie = new Cookie("jwt", accessToken); + cookie.setHttpOnly(true); + cookie.setSecure(false); + cookie.setPath("/"); + cookie.setMaxAge(/*(int) settings.getRefreshTokenTtl().toSeconds()*/ 3600); + response.addCookie(cookie); + + return ResponseEntity.ok("Jwt access was updated."); + + } + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("No cookie here."); + } + } class LoginRequest { diff --git a/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java b/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java index 6aaafc0..2f0c6f7 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java @@ -19,6 +19,11 @@ @Slf4j @Component public class JWTRequestFilter extends OncePerRequestFilter { + JWTUtils jwtUtils; + + public JWTRequestFilter(JWTUtils jwtUtils) { + this.jwtUtils = jwtUtils; + } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { @@ -26,6 +31,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse String token = null; if (request.getCookies() != null) { for (var cookie : request.getCookies()) { + log.info("Cookie: " + cookie.getName()); if ("jwt".equals(cookie.getName())) { token = cookie.getValue(); break; @@ -36,8 +42,8 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse log.info("Got token."); try { - String username = JWTUtils.getUsernameFromToken(token); - List roles = JWTUtils.getRolesFromToken(token); + String username = jwtUtils.getUsernameFromToken(token); + List roles = jwtUtils.getRolesFromToken(token); log.info("{} has jwt. His roles: {}", username, roles); List authorities = roles.stream() diff --git a/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java b/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java index d242006..860a1ea 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java @@ -1,22 +1,28 @@ package codzilla.backend.authservice.JWTUtils; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; +import codzilla.backend.authservice.config.Settings; +import io.jsonwebtoken.*; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.User; import org.springframework.stereotype.Component; import javax.crypto.SecretKey; import java.util.Date; import java.util.List; +import java.util.UUID; @Component public class JWTUtils { private static SecretKey secret = Jwts.SIG.HS256.key().build(); + private final Settings settings; - public static String generateToken(Authentication authentication) { + public JWTUtils(Settings settings) { + this.settings = settings; + } + + public String generateAccessToken(Authentication authentication) { List roles = authentication.getAuthorities().stream() .map(GrantedAuthority::getAuthority) .toList(); @@ -25,12 +31,22 @@ public static String generateToken(Authentication authentication) { .subject(authentication.getName()) .claim("roles", roles) .issuedAt(new Date()) - .expiration(new Date(System.currentTimeMillis() + 86400000)) + .expiration(new Date(System.currentTimeMillis() + settings.getAccessTokenTtl().toMillis())) + .signWith(secret) + .compact(); + } + + public String generateRefreshToken(Authentication authentication) { + return Jwts.builder() + .subject(authentication.getName()) + .setId(UUID.randomUUID().toString()) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + settings.getRefreshTokenTtl().toMillis())) .signWith(secret) .compact(); } - public static List getRolesFromToken(String token) { + public List getRolesFromToken(String token) { Claims claims = Jwts.parser() .verifyWith(secret) .build() @@ -40,7 +56,7 @@ public static List getRolesFromToken(String token) { return claims.get("roles", List.class); } - public static String getUsernameFromToken(String token) { + public String getUsernameFromToken(String token) { return Jwts.parser() .verifyWith(secret) .build() @@ -48,5 +64,18 @@ public static String getUsernameFromToken(String token) { .getPayload() .getSubject(); } + + public boolean validateToken(String token) { + try { + Jwts.parser() + .verifyWith(secret) + .build() + .parseSignedClaims(token); + return true; + } catch (Exception e){ + return false; + } + + } } diff --git a/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java b/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java index 617f7ea..8d106bc 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java @@ -14,5 +14,10 @@ public String getLoginPage() { public String getSignUpPage() { return "signup.html"; } + + @GetMapping("/testrefresh") + public String getTestRefreshPage() { + return "test_refresh.html"; + } } diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/RedisConfig.java b/AuthService/src/main/java/codzilla/backend/authservice/config/RedisConfig.java new file mode 100644 index 0000000..fd283fa --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/config/RedisConfig.java @@ -0,0 +1,26 @@ +package codzilla.backend.authservice.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@Configuration +public class RedisConfig { + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(connectionFactory); + + template.setKeySerializer(new StringRedisSerializer()); + + template.setValueSerializer(new StringRedisSerializer()); + + template.setHashKeySerializer(new StringRedisSerializer()); + template.setHashValueSerializer(new StringRedisSerializer()); + + return template; + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java b/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java index 4d49c9a..37ee103 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java @@ -1,6 +1,7 @@ package codzilla.backend.authservice.config; import codzilla.backend.authservice.JWTRequestFilter.JWTRequestFilter; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; @@ -15,6 +16,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import java.util.Arrays; +import java.util.List; @Configuration @EnableMethodSecurity @@ -26,7 +28,8 @@ public SecurityFilterChain filterChain(HttpSecurity http, JWTRequestFilter filte .csrf(csrf -> csrf.disable()) .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(auth -> auth - .requestMatchers("/auth/login", "/login", "/login.html", "/auth/logout", "/auth/signup", "/signup", "/signup.html").permitAll() + .requestMatchers("/auth/login", "/login", "/login.html", "/auth/logout", "/auth/signup", + "/signup", "/signup.html", "/auth/refresh").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated() ) @@ -43,8 +46,8 @@ public AuthenticationManager authManager(AuthenticationConfiguration config) thr @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); // Твой фронт - configuration.setAllowCredentials(true); // РАЗРЕШАЕМ КУКИ + configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); + configuration.setAllowCredentials(true); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); @@ -52,4 +55,6 @@ public CorsConfigurationSource corsConfigurationSource() { source.registerCorsConfiguration("/**", configuration); return source; } + + } \ No newline at end of file diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/Settings.java b/AuthService/src/main/java/codzilla/backend/authservice/config/Settings.java new file mode 100644 index 0000000..b3c5292 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/config/Settings.java @@ -0,0 +1,16 @@ +package codzilla.backend.authservice.config; + +import jakarta.annotation.PostConstruct; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import java.time.Duration; + +@Configuration +@ConfigurationProperties(prefix = "app.security.jwt") +@Data +public class Settings { + private Duration accessTokenTtl; + private Duration refreshTokenTtl; +} diff --git a/AuthService/src/main/resources/application.properties b/AuthService/src/main/resources/application.properties index 619f739..13fd094 100644 --- a/AuthService/src/main/resources/application.properties +++ b/AuthService/src/main/resources/application.properties @@ -1 +1,3 @@ -spring.application.name=AuthService \ No newline at end of file +spring.application.name=AuthService +app.security.jwt.access-token-ttl=5s +app.security.jwt.refresh-token-ttl=20s \ No newline at end of file From 4a12e78f38767df02af754f22e8f04fc43e2a691 Mon Sep 17 00:00:00 2001 From: toximu Date: Fri, 6 Mar 2026 19:56:12 +0300 Subject: [PATCH 03/11] fix returning statuses --- .../authservice/AdminAccessDeniedHandler.java | 24 ++++++++++ .../AdminController/AdminController.java | 3 ++ .../authservice/HttpStatusEntryPoint.java | 22 +++++++++ .../JWTRequestFilter/JWTRequestFilter.java | 4 ++ .../ViewController/ViewController.java | 4 -- .../authservice/config/SecurityConfig.java | 45 +++++++++---------- .../src/main/resources/application.properties | 4 +- 7 files changed, 76 insertions(+), 30 deletions(-) create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java b/AuthService/src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java new file mode 100644 index 0000000..b15c1af --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java @@ -0,0 +1,24 @@ +package codzilla.backend.authservice; + + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +public class AdminAccessDeniedHandler implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, + HttpServletResponse response, + AccessDeniedException accessDeniedException) throws IOException { + + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + response.setContentType("application/json"); + response.getWriter().write("{\"error\": \"Forbidden\", \"message\": \"You don't have rights to access this page.\"}"); + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java b/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java index dba046b..054a90d 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java @@ -1,5 +1,6 @@ package codzilla.backend.authservice.AdminController; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -7,7 +8,9 @@ @RestController @RequestMapping("/admin") public class AdminController { + @GetMapping("/") + @PreAuthorize("hasRole('ADMIN')") String getAdminInfo() { return "Some admin info."; } diff --git a/AuthService/src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java b/AuthService/src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java new file mode 100644 index 0000000..4031ea8 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java @@ -0,0 +1,22 @@ +package codzilla.backend.authservice; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Component +public class HttpStatusEntryPoint implements AuthenticationEntryPoint { + @Override + public void commence( + HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + response.setContentType("application/json"); + response.getWriter().write("{\"error\": \"Unauthorized\", \"message\": \"You are not logged in.\"}"); + } +} \ No newline at end of file diff --git a/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java b/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java index 2f0c6f7..e7c20f9 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java @@ -8,6 +8,7 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @@ -62,6 +63,9 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse } catch (Exception e) { log.error("dont auth user"); } + } else { + response.setStatus(401); + } filterChain.doFilter(request, response); diff --git a/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java b/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java index 8d106bc..24e73be 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java @@ -15,9 +15,5 @@ public String getSignUpPage() { return "signup.html"; } - @GetMapping("/testrefresh") - public String getTestRefreshPage() { - return "test_refresh.html"; - } } diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java b/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java index 37ee103..81e96ce 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java @@ -1,6 +1,9 @@ package codzilla.backend.authservice.config; +import codzilla.backend.authservice.AdminAccessDeniedHandler; +import codzilla.backend.authservice.HttpStatusEntryPoint; import codzilla.backend.authservice.JWTRequestFilter.JWTRequestFilter; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -10,6 +13,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; @@ -22,20 +26,26 @@ @EnableMethodSecurity public class SecurityConfig { + private static final String[] WHITELIST = {"/auth/**", "/login", "/login.html", "/signup", "/signup.html", "/auth/refresh"}; + + + private final HttpStatusEntryPoint unauthorizedHandler; + private final AdminAccessDeniedHandler adminAccessDeniedHandler; + public SecurityConfig(HttpStatusEntryPoint unauthorizedHandler, AdminAccessDeniedHandler adminAccessDeniedHandler) { + this.unauthorizedHandler = unauthorizedHandler; + this.adminAccessDeniedHandler = adminAccessDeniedHandler; + } + @Bean public SecurityFilterChain filterChain(HttpSecurity http, JWTRequestFilter filter) throws Exception { - return http - .csrf(csrf -> csrf.disable()) - .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests(auth -> auth - .requestMatchers("/auth/login", "/login", "/login.html", "/auth/logout", "/auth/signup", - "/signup", "/signup.html", "/auth/refresh").permitAll() - .requestMatchers("/admin/**").hasRole("ADMIN") - .anyRequest().authenticated() + return http.csrf(csrf -> csrf.disable()) + .exceptionHandling(exception -> exception + .authenticationEntryPoint(unauthorizedHandler) + .accessDeniedHandler(adminAccessDeniedHandler) ) - .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class) - .build(); - + .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) + .authorizeHttpRequests(auth -> auth.requestMatchers(WHITELIST).permitAll().anyRequest().authenticated()) + .addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class).build(); } @Bean @@ -43,18 +53,5 @@ public AuthenticationManager authManager(AuthenticationConfiguration config) thr return config.getAuthenticationManager(); } - @Bean - public CorsConfigurationSource corsConfigurationSource() { - CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000")); - configuration.setAllowCredentials(true); - configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE")); - configuration.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type")); - - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", configuration); - return source; - } - } \ No newline at end of file diff --git a/AuthService/src/main/resources/application.properties b/AuthService/src/main/resources/application.properties index 13fd094..1782c27 100644 --- a/AuthService/src/main/resources/application.properties +++ b/AuthService/src/main/resources/application.properties @@ -1,3 +1,3 @@ spring.application.name=AuthService -app.security.jwt.access-token-ttl=5s -app.security.jwt.refresh-token-ttl=20s \ No newline at end of file +app.security.jwt.access-token-ttl=10m +app.security.jwt.refresh-token-ttl=7d \ No newline at end of file From df53d0a26589c868ea0395d234307647db3b41f9 Mon Sep 17 00:00:00 2001 From: toximu Date: Wed, 11 Mar 2026 11:17:38 +0300 Subject: [PATCH 04/11] integrate with postgre, add exceptions, dto, start tests --- AuthService/build.gradle | 7 +- AuthService/compose.yaml | 20 +++++ .../AdminController/AdminController.java | 17 +++- .../AuthController/AuthController.java | 70 +++++++--------- .../authservice/AuthExceptionHandler.java | 39 +++++++++ .../authservice/Exceptions/RestException.java | 14 ++++ .../UserAlreadyExistsException.java | 9 ++ .../Exceptions/UserNotFoundException.java | 9 ++ .../Exceptions/UsernameIsTakenException.java | 9 ++ .../JWTRequestFilter/JWTRequestFilter.java | 3 +- .../authservice/JWTUtils/JWTUtils.java | 3 +- .../Repository/UserRepository.java | 12 +++ .../RepositoryUserDetailsService.java | 27 ++++++ .../codzilla/backend/authservice/User.java | 62 ++++++++++++++ .../backend/authservice/UserService.java | 78 ++++++++++++++++++ .../authservice/config/SecurityConfig.java | 20 ++++- .../authservice/config/UserConfig.java | 20 ----- .../authservice/dto/ErrorResponseDTO.java | 16 ++++ .../authservice/dto/LoginRequestDTO.java | 7 ++ .../authservice/dto/LoginResponseDTO.java | 6 ++ .../authservice/dto/RegisterRequestDTO.java | 8 ++ .../authservice/dto/RegisterResponseDTO.java | 6 ++ .../authservice/dto/UserResponseDTO.java | 11 +++ .../src/main/resources/application.properties | 9 +- .../AuthServiceApplicationTests.java | 1 + .../authservice/BaseIntegrationTest.java | 24 ++++++ .../authservice/RegisterIntegrationTest.java | 71 ++++++++++++++++ .../src/test/resources/application.properties | 13 +++ .../.gradle/9.3.1/checksums/checksums.lock | Bin 0 -> 17 bytes .../.gradle/9.3.1/checksums/md5-checksums.bin | Bin 0 -> 29697 bytes .../9.3.1/checksums/sha1-checksums.bin | Bin 0 -> 38315 bytes .../.gradle/9.3.1/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/9.3.1/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes Backend/.gradle/9.3.1/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + Backend/.gradle/vcs-1/gc.properties | 0 37 files changed, 525 insertions(+), 68 deletions(-) create mode 100644 AuthService/compose.yaml create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/Exceptions/RestException.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/Repository/UserRepository.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/User.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/UserService.java delete mode 100644 AuthService/src/main/java/codzilla/backend/authservice/config/UserConfig.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java create mode 100644 AuthService/src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java create mode 100644 AuthService/src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java create mode 100644 AuthService/src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java create mode 100644 AuthService/src/test/resources/application.properties create mode 100644 Backend/.gradle/9.3.1/checksums/checksums.lock create mode 100644 Backend/.gradle/9.3.1/checksums/md5-checksums.bin create mode 100644 Backend/.gradle/9.3.1/checksums/sha1-checksums.bin create mode 100644 Backend/.gradle/9.3.1/fileChanges/last-build.bin create mode 100644 Backend/.gradle/9.3.1/fileHashes/fileHashes.lock create mode 100644 Backend/.gradle/9.3.1/gc.properties create mode 100644 Backend/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 Backend/.gradle/buildOutputCleanup/cache.properties create mode 100644 Backend/.gradle/vcs-1/gc.properties diff --git a/AuthService/build.gradle b/AuthService/build.gradle index 830cbb0..360789e 100644 --- a/AuthService/build.gradle +++ b/AuthService/build.gradle @@ -21,12 +21,17 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-webmvc' - implementation('org.springframework.boot:spring-boot-starter-data-redis') + implementation 'org.springframework.boot:spring-boot-starter-data-redis' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' + runtimeOnly 'org.postgresql:postgresql' compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-security-test' testImplementation 'org.springframework.boot:spring-boot-starter-webmvc-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + testRuntimeOnly 'com.h2database:h2' + testImplementation 'org.springframework.boot:spring-boot-starter-test' + implementation 'io.jsonwebtoken:jjwt-api:0.12.5' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' diff --git a/AuthService/compose.yaml b/AuthService/compose.yaml new file mode 100644 index 0000000..ccdc4c7 --- /dev/null +++ b/AuthService/compose.yaml @@ -0,0 +1,20 @@ +services: + postgres: + container_name: codzilla_postgres + image: postgres:15 + ports: + - "5433:5432" + environment: + POSTGRES_DB: testingdb + POSTGRES_USER: myuser + POSTGRES_PASSWORD: secret + volumes: + - postgres_data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U myuser -d testingdb"] + interval: 10s + timeout: 5s + retries: 5 + +volumes: + postgres_data: \ No newline at end of file diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java b/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java index 054a90d..9086765 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java @@ -1,5 +1,7 @@ package codzilla.backend.authservice.AdminController; +import codzilla.backend.authservice.UserService; +import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -7,11 +9,22 @@ @RestController @RequestMapping("/admin") +@PreAuthorize("hasAuthority('ADMIN')") public class AdminController { - @GetMapping("/") - @PreAuthorize("hasRole('ADMIN')") + private final UserService userService; + + public AdminController(UserService userService) { + this.userService = userService; + } + + @GetMapping("/info") String getAdminInfo() { return "Some admin info."; } + + @GetMapping("/users") + ResponseEntity getAllUsers() { + return ResponseEntity.ok(userService.getAllUsers()); + } } diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java b/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java index 811926a..ae5b41b 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java @@ -1,7 +1,13 @@ package codzilla.backend.authservice.AuthController; import codzilla.backend.authservice.JWTUtils.JWTUtils; +import codzilla.backend.authservice.User; +import codzilla.backend.authservice.UserService; import codzilla.backend.authservice.config.Settings; +import codzilla.backend.authservice.dto.LoginRequestDTO; +import codzilla.backend.authservice.dto.LoginResponseDTO; +import codzilla.backend.authservice.dto.RegisterRequestDTO; +import codzilla.backend.authservice.dto.RegisterResponseDTO; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -12,37 +18,37 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; -import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.web.bind.annotation.*; +import java.util.Map; + @Slf4j @RestController @RequestMapping("/auth") public class AuthController { private final AuthenticationManager authManager; - private final InMemoryUserDetailsManager manager; - private final PasswordEncoder encoder; private final JWTUtils jwtUtils; private final Settings settings; + private final UserService userService; @Autowired - public AuthController(AuthenticationManager authManager, InMemoryUserDetailsManager manager, PasswordEncoder encoder, - JWTUtils jwtUtils, Settings settings) { - this.manager = manager; - this.encoder = encoder; + public AuthController(AuthenticationManager authManager, + JWTUtils jwtUtils, Settings settings, UserService userService) { + this.userService = userService; this.authManager = authManager; this.jwtUtils = jwtUtils; this.settings = settings; } @PostMapping("/login") - public ResponseEntity login(@RequestBody LoginRequest req, HttpServletResponse response) { + public ResponseEntity login(@RequestBody LoginRequestDTO request, HttpServletResponse response) { log.info("Auth user by password..."); + log.info(request.email() + request.rawPassword()); Authentication auth = authManager.authenticate( - new UsernamePasswordAuthenticationToken(req.username, req.password) + new UsernamePasswordAuthenticationToken(request.email(), request.rawPassword()) ); var accessToken = jwtUtils.generateAccessToken(auth); @@ -50,19 +56,19 @@ public ResponseEntity login(@RequestBody LoginRequest req, HttpServletRespons jwtCookie.setHttpOnly(true); jwtCookie.setSecure(false); jwtCookie.setPath("/"); - jwtCookie.setMaxAge(/*(int) settings.getRefreshTokenTtl().toSeconds()*/ 3600); + jwtCookie.setMaxAge((int) settings.getRefreshTokenTtl().toSeconds()); response.addCookie(jwtCookie); var refreshToken = jwtUtils.generateRefreshToken(auth); Cookie refreshCookie = new Cookie("refresh_jwt", refreshToken); refreshCookie.setPath("/"); refreshCookie.setHttpOnly(true); - refreshCookie.setMaxAge(/*(int) settings.getRefreshTokenTtl().toSeconds()*/ 3600); + refreshCookie.setMaxAge((int) settings.getRefreshTokenTtl().toSeconds()); refreshCookie.setSecure(false); response.addCookie(refreshCookie); - UserDetails user = (UserDetails) auth.getPrincipal(); - return ResponseEntity.ok("You are logged in! Your roles are " + user.getAuthorities().toString() + "."); + UserDetails user = userService.getByEmail(request.email()); + return ResponseEntity.ok(new LoginResponseDTO(user.getUsername())); } @PostMapping("/logout") @@ -79,15 +85,9 @@ public ResponseEntity logout(HttpServletResponse response) { @PostMapping("/signup") - public ResponseEntity signUp(@RequestBody SignupRequest request) { - - UserDetails userDetails = User. - withUsername(request.username). - password(encoder.encode(request.password)). - roles("USER").build(); - manager.createUser(userDetails); - - return ResponseEntity.ok("User created!"); + public ResponseEntity signUp(@RequestBody RegisterRequestDTO request) { + userService.registerUser(request); + return ResponseEntity.ok(new RegisterResponseDTO(request.username())); } @PostMapping("/refresh") @@ -105,14 +105,14 @@ public ResponseEntity refreshToken(HttpServletRequest request, HttpServletRes if (!jwtUtils.validateToken(refreshToken)) return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Token is wrong."); - String username = jwtUtils.getUsernameFromToken(refreshToken); + String email = jwtUtils.getEmailFromToken(refreshToken); - UserDetails userDetails = manager.loadUserByUsername(username); + User user = userService.getByEmail(email); UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken( - userDetails, + user, null, - userDetails.getAuthorities() + user.getAuthorities() ); var accessToken = jwtUtils.generateAccessToken(auth); @@ -120,23 +120,17 @@ public ResponseEntity refreshToken(HttpServletRequest request, HttpServletRes cookie.setHttpOnly(true); cookie.setSecure(false); cookie.setPath("/"); - cookie.setMaxAge(/*(int) settings.getRefreshTokenTtl().toSeconds()*/ 3600); + cookie.setMaxAge((int) settings.getRefreshTokenTtl().toSeconds()); response.addCookie(cookie); - return ResponseEntity.ok("Jwt access was updated."); } return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("No cookie here."); } -} - -class LoginRequest { - public String username; - public String password; -} + @PostMapping("/create-admin") + void createAdmin() { + userService.createAdmin(); + } -class SignupRequest { - public String username; - public String password; -} +} \ No newline at end of file diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java b/AuthService/src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java new file mode 100644 index 0000000..e22b3b6 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java @@ -0,0 +1,39 @@ +package codzilla.backend.authservice; + +import codzilla.backend.authservice.Exceptions.RestException; +import codzilla.backend.authservice.Exceptions.UserAlreadyExistsException; +import codzilla.backend.authservice.Exceptions.UserNotFoundException; +import codzilla.backend.authservice.Exceptions.UsernameIsTakenException; +import codzilla.backend.authservice.dto.ErrorResponseDTO; +import org.apache.coyote.BadRequestException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; +import tools.jackson.databind.ObjectMapper; + +import java.util.HashMap; +import java.util.Map; + +@RestControllerAdvice +public class AuthExceptionHandler { + @Autowired + ObjectMapper objectMapper; + + @ExceptionHandler(RestException.class) + public ResponseEntity handleUserNotFound(RestException exception) { + ErrorResponseDTO dto = new ErrorResponseDTO(exception); + return new ResponseEntity<>(objectMapper.writeValueAsString(dto), exception.getStatus()); + } + + @ExceptionHandler(BadCredentialsException.class) + public ResponseEntity handleWrongCredentials(BadCredentialsException exception){ + ErrorResponseDTO dto = new ErrorResponseDTO( + "Wrong email or password", + HttpStatus.UNAUTHORIZED + ); + return new ResponseEntity<>(objectMapper.writeValueAsString(dto), HttpStatus.UNAUTHORIZED); + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/RestException.java b/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/RestException.java new file mode 100644 index 0000000..8c7ea37 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/RestException.java @@ -0,0 +1,14 @@ +package codzilla.backend.authservice.Exceptions; + +import lombok.Data; +import org.springframework.http.HttpStatus; + +@Data +public class RestException extends RuntimeException { + HttpStatus status; + + RestException(HttpStatus status, String message) { + super(message); + this.status = status; + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java b/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java new file mode 100644 index 0000000..1e727d1 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java @@ -0,0 +1,9 @@ +package codzilla.backend.authservice.Exceptions; + +import org.springframework.http.HttpStatus; + +public class UserAlreadyExistsException extends RestException { + public UserAlreadyExistsException() { + super(HttpStatus.CONFLICT, "User already exists"); + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java b/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java new file mode 100644 index 0000000..a044152 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java @@ -0,0 +1,9 @@ +package codzilla.backend.authservice.Exceptions; + +import org.springframework.http.HttpStatus; + +public class UserNotFoundException extends RestException { + public UserNotFoundException() { + super(HttpStatus.CONFLICT, "User not found"); + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java b/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java new file mode 100644 index 0000000..c1d79a5 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java @@ -0,0 +1,9 @@ +package codzilla.backend.authservice.Exceptions; + +import org.springframework.http.HttpStatus; + +public class UsernameIsTakenException extends RestException { + public UsernameIsTakenException() { + super(HttpStatus.CONFLICT, "Username is taken"); + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java b/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java index e7c20f9..a958118 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java @@ -8,7 +8,6 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; @@ -43,7 +42,7 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse log.info("Got token."); try { - String username = jwtUtils.getUsernameFromToken(token); + String username = jwtUtils.getEmailFromToken(token); List roles = jwtUtils.getRolesFromToken(token); log.info("{} has jwt. His roles: {}", username, roles); diff --git a/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java b/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java index 860a1ea..bfef082 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java @@ -2,7 +2,6 @@ import codzilla.backend.authservice.config.Settings; import io.jsonwebtoken.*; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Component; @@ -56,7 +55,7 @@ public List getRolesFromToken(String token) { return claims.get("roles", List.class); } - public String getUsernameFromToken(String token) { + public String getEmailFromToken(String token) { return Jwts.parser() .verifyWith(secret) .build() diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Repository/UserRepository.java b/AuthService/src/main/java/codzilla/backend/authservice/Repository/UserRepository.java new file mode 100644 index 0000000..19a5d1c --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/Repository/UserRepository.java @@ -0,0 +1,12 @@ +package codzilla.backend.authservice.Repository; + +import codzilla.backend.authservice.User; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.Optional; + +public interface UserRepository extends JpaRepository { + boolean existsByEmail(String email); + boolean existsByUsername(String username); + Optional findByEmail(String email); +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java b/AuthService/src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java new file mode 100644 index 0000000..8333e85 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java @@ -0,0 +1,27 @@ +package codzilla.backend.authservice; + +import codzilla.backend.authservice.Repository.UserRepository; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +@Service +public class RepositoryUserDetailsService implements UserDetailsService { + private final UserRepository userRepository; + + public RepositoryUserDetailsService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + var user = userRepository.findByEmail(username); + + if (user.isPresent()) { + return user.get(); + } else { + throw new UsernameNotFoundException("There is no user with email: " + username); + } + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/User.java b/AuthService/src/main/java/codzilla/backend/authservice/User.java new file mode 100644 index 0000000..83d6c0d --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/User.java @@ -0,0 +1,62 @@ +package codzilla.backend.authservice; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.jspecify.annotations.Nullable; +import org.springframework.security.core.CredentialsContainer; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.AuthorityUtils; +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.UsernameNotFoundException; + + +import java.util.Collection; +import java.util.List; + +@Data +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "users") +public class User implements UserDetails, CredentialsContainer { + + private String username; + private String password; + private String email; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Builder.Default + private List authorities = AuthorityUtils.createAuthorityList("USER"); + + @Override + public void eraseCredentials() { + + } + + @Override + public Collection getAuthorities() { + if (this.authorities == null) { + return List.of(new SimpleGrantedAuthority("ROLE_USER")); + } + return this.authorities; + } + @Override + public @Nullable String getPassword() { + return password; + } + + // returns email + @Override + public String getUsername() { + return email; + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/UserService.java b/AuthService/src/main/java/codzilla/backend/authservice/UserService.java new file mode 100644 index 0000000..4d7e509 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/UserService.java @@ -0,0 +1,78 @@ +package codzilla.backend.authservice; + +import codzilla.backend.authservice.Exceptions.UserAlreadyExistsException; +import codzilla.backend.authservice.Exceptions.UserNotFoundException; +import codzilla.backend.authservice.Exceptions.UsernameIsTakenException; +import codzilla.backend.authservice.Repository.UserRepository; +import codzilla.backend.authservice.dto.RegisterRequestDTO; +import codzilla.backend.authservice.dto.UserResponseDTO; +import org.springframework.http.HttpStatus; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; + +@Service +public class UserService { + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) { + this.userRepository = userRepository; + this.passwordEncoder = passwordEncoder; + } + + public void registerUser(RegisterRequestDTO dto) throws UserAlreadyExistsException { + if (userRepository.existsByEmail(dto.email())) { + throw new UserAlreadyExistsException(); + } + + if (userRepository.existsByUsername(dto.username())) { + throw new UsernameIsTakenException(); + } + + var user = User.builder() + .email(dto.email()) + .username(dto.username()) + .password(passwordEncoder.encode(dto.rawPassword())).build(); + userRepository.save(user); + + } + + public User getByEmail(String email) { + var user = userRepository.findByEmail(email); + if (user.isPresent()) { + return user.get(); + } else { + throw new UserNotFoundException(); + } + } + + public List getAllUsers() { + return userRepository.findAll().stream() + .map(user -> new UserResponseDTO( + user.getUsername(), + user.getEmail(), + user.getId(), + user.getAuthorities().stream() + .map(GrantedAuthority::getAuthority).toList())) + .toList(); + } + + + public void createAdmin() { + if (!userRepository.existsByUsername("admin")) { + User admin = User.builder() + .username("admin") + .email("admin") + .password(passwordEncoder.encode("0")) + .authorities(List.of(new SimpleGrantedAuthority("ADMIN"))) + .build(); + userRepository.save(admin); + } + } + +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java b/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java index 81e96ce..de1d825 100644 --- a/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java +++ b/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java @@ -18,6 +18,7 @@ import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import tools.jackson.databind.ObjectMapper; import java.util.Arrays; import java.util.List; @@ -26,11 +27,12 @@ @EnableMethodSecurity public class SecurityConfig { - private static final String[] WHITELIST = {"/auth/**", "/login", "/login.html", "/signup", "/signup.html", "/auth/refresh"}; + private static final String[] WHITELIST = {"/auth/**", "/login", "/login.html", "/signup", "/signup.html"}; private final HttpStatusEntryPoint unauthorizedHandler; private final AdminAccessDeniedHandler adminAccessDeniedHandler; + public SecurityConfig(HttpStatusEntryPoint unauthorizedHandler, AdminAccessDeniedHandler adminAccessDeniedHandler) { this.unauthorizedHandler = unauthorizedHandler; this.adminAccessDeniedHandler = adminAccessDeniedHandler; @@ -38,7 +40,16 @@ public SecurityConfig(HttpStatusEntryPoint unauthorizedHandler, AdminAccessDenie @Bean public SecurityFilterChain filterChain(HttpSecurity http, JWTRequestFilter filter) throws Exception { - return http.csrf(csrf -> csrf.disable()) + return http + .cors(cors -> cors.configurationSource(request -> { + CorsConfiguration config = new CorsConfiguration(); + config.setAllowedOrigins(Arrays.asList("http://localhost:5173")); // Твой порт Vite + config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); + config.setAllowedHeaders(Arrays.asList("*")); + config.setAllowCredentials(true); + return config; + })) + .csrf(csrf -> csrf.disable()) .exceptionHandling(exception -> exception .authenticationEntryPoint(unauthorizedHandler) .accessDeniedHandler(adminAccessDeniedHandler) @@ -53,5 +64,10 @@ public AuthenticationManager authManager(AuthenticationConfiguration config) thr return config.getAuthenticationManager(); } + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper(); + } + } \ No newline at end of file diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/UserConfig.java b/AuthService/src/main/java/codzilla/backend/authservice/config/UserConfig.java deleted file mode 100644 index c7d64e0..0000000 --- a/AuthService/src/main/java/codzilla/backend/authservice/config/UserConfig.java +++ /dev/null @@ -1,20 +0,0 @@ -package codzilla.backend.authservice.config; - - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; - -@Configuration -public class UserConfig { - - @Bean - public InMemoryUserDetailsManager inMemoryUserDetailsManager(PasswordEncoder encoder) { - return new InMemoryUserDetailsManager( - User.withUsername("admin").password(encoder.encode("admin")).roles("ADMIN").build(), - User.withUsername("user").password(encoder.encode("user")).roles("USER").build() - ); - } -} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java b/AuthService/src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java new file mode 100644 index 0000000..d45d318 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java @@ -0,0 +1,16 @@ +package codzilla.backend.authservice.dto; + +import codzilla.backend.authservice.Exceptions.RestException; +import org.springframework.http.HttpStatus; + +public record ErrorResponseDTO( + String message, + HttpStatus status +) { + public ErrorResponseDTO(RestException exception) { + this( + exception.getMessage(), + exception.getStatus() + ); + } +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java b/AuthService/src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java new file mode 100644 index 0000000..26f544d --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java @@ -0,0 +1,7 @@ +package codzilla.backend.authservice.dto; + +public record LoginRequestDTO( + String email, + String rawPassword +) { +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java b/AuthService/src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java new file mode 100644 index 0000000..8263dad --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java @@ -0,0 +1,6 @@ +package codzilla.backend.authservice.dto; + +public record LoginResponseDTO( + String username +) { +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java b/AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java new file mode 100644 index 0000000..f942c35 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java @@ -0,0 +1,8 @@ +package codzilla.backend.authservice.dto; + +public record RegisterRequestDTO( + String username, + String email, + String rawPassword +) { +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java b/AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java new file mode 100644 index 0000000..21866d8 --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java @@ -0,0 +1,6 @@ +package codzilla.backend.authservice.dto; + +public record RegisterResponseDTO( + String username +) { +} diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java b/AuthService/src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java new file mode 100644 index 0000000..e8fe14d --- /dev/null +++ b/AuthService/src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java @@ -0,0 +1,11 @@ +package codzilla.backend.authservice.dto; + +import java.util.List; + +public record UserResponseDTO( + String username, + String email, + Long id, + List authorities +) { +} diff --git a/AuthService/src/main/resources/application.properties b/AuthService/src/main/resources/application.properties index 1782c27..6592970 100644 --- a/AuthService/src/main/resources/application.properties +++ b/AuthService/src/main/resources/application.properties @@ -1,3 +1,10 @@ spring.application.name=AuthService app.security.jwt.access-token-ttl=10m -app.security.jwt.refresh-token-ttl=7d \ No newline at end of file +app.security.jwt.refresh-token-ttl=7d + +spring.datasource.url=${DB_URL} +spring.datasource.username=${DB_USERNAME} +spring.datasource.password=${DB_PASSWORD} +spring.jpa.hibernate.ddl-auto=update + +#logging.level.org.springframework.security=DEBUG \ No newline at end of file diff --git a/AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java b/AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java index c66d2bd..1b7a8e9 100644 --- a/AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java +++ b/AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java @@ -8,6 +8,7 @@ class AuthServiceApplicationTests { @Test void contextLoads() { + assert (true); } } diff --git a/AuthService/src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java b/AuthService/src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java new file mode 100644 index 0000000..872a156 --- /dev/null +++ b/AuthService/src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java @@ -0,0 +1,24 @@ +package codzilla.backend.authservice; + +import codzilla.backend.authservice.Repository.UserRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.transaction.annotation.Transactional; +import tools.jackson.databind.ObjectMapper; + + +@SpringBootTest +@AutoConfigureMockMvc +@Transactional +public class BaseIntegrationTest { + @Autowired + protected MockMvc mockMvc; + + @Autowired + protected ObjectMapper objectMapper; + + @Autowired + protected UserRepository userRepository; +} diff --git a/AuthService/src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java b/AuthService/src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java new file mode 100644 index 0000000..c042526 --- /dev/null +++ b/AuthService/src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java @@ -0,0 +1,71 @@ +package codzilla.backend.authservice; + +import codzilla.backend.authservice.Exceptions.UserAlreadyExistsException; +import codzilla.backend.authservice.dto.ErrorResponseDTO; +import codzilla.backend.authservice.dto.RegisterRequestDTO; +import codzilla.backend.authservice.dto.RegisterResponseDTO; +import jakarta.transaction.Transactional; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.http.MediaType; +import org.springframework.security.crypto.password.PasswordEncoder; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@Transactional +@AutoConfigureMockMvc +public class RegisterIntegrationTest extends BaseIntegrationTest { + + @Autowired + PasswordEncoder passwordEncoder; + + @Test + public void testSignUpSimple() throws Exception { + RegisterRequestDTO request = new RegisterRequestDTO("user", "email", "password"); + + RegisterResponseDTO expectedResponse = new RegisterResponseDTO("user"); + + mockMvc.perform( + post("/auth/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isOk()) + .andExpect(content().json(objectMapper.writeValueAsString(expectedResponse))); + + assert (userRepository.existsByEmail(request.email())); + assert (userRepository.existsByUsername(request.username())); + User addedUser = userRepository.findByEmail(request.email()).get(); + assert (addedUser.getAuthorities().stream().allMatch(s -> { + return "USER".equals(s.getAuthority()); + })); + assertThat(passwordEncoder.matches( + request.rawPassword(), + addedUser.getPassword() + )); + } + + @Test + public void testUserAlreadyExists() throws Exception { + RegisterRequestDTO request1 = new RegisterRequestDTO("user1", "email", "password"); + RegisterRequestDTO request2 = new RegisterRequestDTO("user2", "email", "password"); + + ErrorResponseDTO expectedError = new ErrorResponseDTO(new UserAlreadyExistsException()); + + mockMvc.perform( + post("/auth/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request1))); + + mockMvc.perform(post("/auth/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request2))) + .andExpect(status().isConflict()) + .andExpect(content().json(objectMapper.writeValueAsString(expectedError))); + } +} diff --git a/AuthService/src/test/resources/application.properties b/AuthService/src/test/resources/application.properties new file mode 100644 index 0000000..7983ec7 --- /dev/null +++ b/AuthService/src/test/resources/application.properties @@ -0,0 +1,13 @@ + +spring.datasource.url=jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1 +spring.datasource.driverClassName=org.h2.Driver +spring.datasource.username=sa +spring.datasource.password= + +spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.show-sql=true + +app.security.jwt.access-token-ttl=10m +app.security.jwt.refresh-token-ttl=7d + +jwt.secret=testSecretKeyForCodzillaProject1234567890 \ No newline at end of file diff --git a/Backend/.gradle/9.3.1/checksums/checksums.lock b/Backend/.gradle/9.3.1/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..7883a18550662f4134e9e493438b318afa13d194 GIT binary patch literal 17 VcmZSn{3rgh+!5Ug3}C<%2>?GN1s?za literal 0 HcmV?d00001 diff --git a/Backend/.gradle/9.3.1/checksums/md5-checksums.bin b/Backend/.gradle/9.3.1/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..b7ba56908edd6dd9f3162f9b5457ac5acd5ea85e GIT binary patch literal 29697 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 literal 0 HcmV?d00001 diff --git a/Backend/.gradle/9.3.1/checksums/sha1-checksums.bin b/Backend/.gradle/9.3.1/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..f6c0d89024c736df4643be5b958981185d6f1e7a GIT binary patch literal 38315 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 U=L+LLeR-hg`u{^;|7|q>AH8--WB>pF literal 0 HcmV?d00001 diff --git a/Backend/.gradle/9.3.1/fileChanges/last-build.bin b/Backend/.gradle/9.3.1/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/Backend/.gradle/9.3.1/fileHashes/fileHashes.lock b/Backend/.gradle/9.3.1/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..dfe459d1d6197e1c6cd49dfad011f0dde4faa411 GIT binary patch literal 17 TcmZQppSZY9n}7CM1}FdkD%S&t literal 0 HcmV?d00001 diff --git a/Backend/.gradle/9.3.1/gc.properties b/Backend/.gradle/9.3.1/gc.properties new file mode 100644 index 0000000..e69de29 diff --git a/Backend/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/Backend/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..3d3344b8a28d5ff8bcaf88416464e0e08ad1fe2f GIT binary patch literal 17 UcmZRcSA3q8UO$Q literal 0 HcmV?d00001 diff --git a/Backend/.gradle/buildOutputCleanup/cache.properties b/Backend/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 0000000..a935e21 --- /dev/null +++ b/Backend/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Thu Feb 26 20:17:48 MSK 2026 +gradle.version=9.3.1 diff --git a/Backend/.gradle/vcs-1/gc.properties b/Backend/.gradle/vcs-1/gc.properties new file mode 100644 index 0000000..e69de29 From 6185bd2c37868f004af68ac09880f9567e9a249a Mon Sep 17 00:00:00 2001 From: toximu Date: Wed, 11 Mar 2026 11:30:44 +0300 Subject: [PATCH 05/11] move files to main directory --- AuthService/.gitattributes => .gitattributes | 0 AuthService/.gitignore => .gitignore | 0 Backend/.gradle/9.3.1/checksums/checksums.lock | Bin 17 -> 0 bytes .../.gradle/9.3.1/checksums/md5-checksums.bin | Bin 29697 -> 0 bytes .../.gradle/9.3.1/checksums/sha1-checksums.bin | Bin 38315 -> 0 bytes .../.gradle/9.3.1/fileChanges/last-build.bin | Bin 1 -> 0 bytes .../.gradle/9.3.1/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes Backend/.gradle/9.3.1/gc.properties | 0 .../buildOutputCleanup/buildOutputCleanup.lock | Bin 17 -> 0 bytes .../.gradle/buildOutputCleanup/cache.properties | 2 -- Backend/.gradle/vcs-1/gc.properties | 0 AuthService/build.gradle => build.gradle | 0 AuthService/compose.yaml => compose.yaml | 0 .../wrapper/gradle-wrapper.jar | Bin .../wrapper/gradle-wrapper.properties | 0 AuthService/gradlew => gradlew | 0 AuthService/gradlew.bat => gradlew.bat | 0 AuthService/settings.gradle => settings.gradle | 0 .../authservice/AdminAccessDeniedHandler.java | 0 .../AdminController/AdminController.java | 0 .../AuthController/AuthController.java | 0 .../authservice/AuthExceptionHandler.java | 0 .../authservice/AuthServiceApplication.java | 0 .../authservice/Exceptions/RestException.java | 0 .../Exceptions/UserAlreadyExistsException.java | 0 .../Exceptions/UserNotFoundException.java | 0 .../Exceptions/UsernameIsTakenException.java | 0 .../authservice/HttpStatusEntryPoint.java | 0 .../JWTRequestFilter/JWTRequestFilter.java | 0 .../backend/authservice/JWTUtils/JWTUtils.java | 0 .../authservice/Repository/UserRepository.java | 0 .../RepositoryUserDetailsService.java | 0 .../SimpleController/SimpleController.java | 0 .../java/codzilla/backend/authservice/User.java | 0 .../backend/authservice/UserService.java | 0 .../ViewController/ViewController.java | 0 .../authservice/config/PasswordConfig.java | 0 .../backend/authservice/config/RedisConfig.java | 0 .../authservice/config/SecurityConfig.java | 0 .../backend/authservice/config/Settings.java | 0 .../authservice/dto/ErrorResponseDTO.java | 0 .../authservice/dto/LoginRequestDTO.java | 0 .../authservice/dto/LoginResponseDTO.java | 0 .../authservice/dto/RegisterRequestDTO.java | 0 .../authservice/dto/RegisterResponseDTO.java | 0 .../authservice/dto/UserResponseDTO.java | 0 .../main/resources/application.properties | 0 .../main/resources/static/login.html | 0 .../main/resources/static/signup.html | 0 .../AuthServiceApplicationTests.java | 0 .../authservice/BaseIntegrationTest.java | 0 .../authservice/RegisterIntegrationTest.java | 0 .../test/resources/application.properties | 0 53 files changed, 2 deletions(-) rename AuthService/.gitattributes => .gitattributes (100%) rename AuthService/.gitignore => .gitignore (100%) delete mode 100644 Backend/.gradle/9.3.1/checksums/checksums.lock delete mode 100644 Backend/.gradle/9.3.1/checksums/md5-checksums.bin delete mode 100644 Backend/.gradle/9.3.1/checksums/sha1-checksums.bin delete mode 100644 Backend/.gradle/9.3.1/fileChanges/last-build.bin delete mode 100644 Backend/.gradle/9.3.1/fileHashes/fileHashes.lock delete mode 100644 Backend/.gradle/9.3.1/gc.properties delete mode 100644 Backend/.gradle/buildOutputCleanup/buildOutputCleanup.lock delete mode 100644 Backend/.gradle/buildOutputCleanup/cache.properties delete mode 100644 Backend/.gradle/vcs-1/gc.properties rename AuthService/build.gradle => build.gradle (100%) rename AuthService/compose.yaml => compose.yaml (100%) rename {AuthService/gradle => gradle}/wrapper/gradle-wrapper.jar (100%) rename {AuthService/gradle => gradle}/wrapper/gradle-wrapper.properties (100%) rename AuthService/gradlew => gradlew (100%) rename AuthService/gradlew.bat => gradlew.bat (100%) rename AuthService/settings.gradle => settings.gradle (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/AdminController/AdminController.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/AuthController/AuthController.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/AuthExceptionHandler.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/AuthServiceApplication.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/Exceptions/RestException.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/Repository/UserRepository.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/User.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/UserService.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/ViewController/ViewController.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/config/PasswordConfig.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/config/RedisConfig.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/config/SecurityConfig.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/config/Settings.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java (100%) rename {AuthService/src => src}/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java (100%) rename {AuthService/src => src}/main/resources/application.properties (100%) rename {AuthService/src => src}/main/resources/static/login.html (100%) rename {AuthService/src => src}/main/resources/static/signup.html (100%) rename {AuthService/src => src}/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java (100%) rename {AuthService/src => src}/test/java/codzilla/backend/authservice/BaseIntegrationTest.java (100%) rename {AuthService/src => src}/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java (100%) rename {AuthService/src => src}/test/resources/application.properties (100%) diff --git a/AuthService/.gitattributes b/.gitattributes similarity index 100% rename from AuthService/.gitattributes rename to .gitattributes diff --git a/AuthService/.gitignore b/.gitignore similarity index 100% rename from AuthService/.gitignore rename to .gitignore diff --git a/Backend/.gradle/9.3.1/checksums/checksums.lock b/Backend/.gradle/9.3.1/checksums/checksums.lock deleted file mode 100644 index 7883a18550662f4134e9e493438b318afa13d194..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 VcmZSn{3rgh+!5Ug3}C<%2>?GN1s?za diff --git a/Backend/.gradle/9.3.1/checksums/md5-checksums.bin b/Backend/.gradle/9.3.1/checksums/md5-checksums.bin deleted file mode 100644 index b7ba56908edd6dd9f3162f9b5457ac5acd5ea85e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29697 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 diff --git a/Backend/.gradle/9.3.1/checksums/sha1-checksums.bin b/Backend/.gradle/9.3.1/checksums/sha1-checksums.bin deleted file mode 100644 index f6c0d89024c736df4643be5b958981185d6f1e7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38315 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 U=L+LLeR-hg`u{^;|7|q>AH8--WB>pF diff --git a/Backend/.gradle/9.3.1/fileChanges/last-build.bin b/Backend/.gradle/9.3.1/fileChanges/last-build.bin deleted file mode 100644 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1 IcmZPo000310RR91 diff --git a/Backend/.gradle/9.3.1/fileHashes/fileHashes.lock b/Backend/.gradle/9.3.1/fileHashes/fileHashes.lock deleted file mode 100644 index dfe459d1d6197e1c6cd49dfad011f0dde4faa411..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 TcmZQppSZY9n}7CM1}FdkD%S&t diff --git a/Backend/.gradle/9.3.1/gc.properties b/Backend/.gradle/9.3.1/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/Backend/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/Backend/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index 3d3344b8a28d5ff8bcaf88416464e0e08ad1fe2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZRcSA3q8UO$Q diff --git a/Backend/.gradle/buildOutputCleanup/cache.properties b/Backend/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index a935e21..0000000 --- a/Backend/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Thu Feb 26 20:17:48 MSK 2026 -gradle.version=9.3.1 diff --git a/Backend/.gradle/vcs-1/gc.properties b/Backend/.gradle/vcs-1/gc.properties deleted file mode 100644 index e69de29..0000000 diff --git a/AuthService/build.gradle b/build.gradle similarity index 100% rename from AuthService/build.gradle rename to build.gradle diff --git a/AuthService/compose.yaml b/compose.yaml similarity index 100% rename from AuthService/compose.yaml rename to compose.yaml diff --git a/AuthService/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from AuthService/gradle/wrapper/gradle-wrapper.jar rename to gradle/wrapper/gradle-wrapper.jar diff --git a/AuthService/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from AuthService/gradle/wrapper/gradle-wrapper.properties rename to gradle/wrapper/gradle-wrapper.properties diff --git a/AuthService/gradlew b/gradlew similarity index 100% rename from AuthService/gradlew rename to gradlew diff --git a/AuthService/gradlew.bat b/gradlew.bat similarity index 100% rename from AuthService/gradlew.bat rename to gradlew.bat diff --git a/AuthService/settings.gradle b/settings.gradle similarity index 100% rename from AuthService/settings.gradle rename to settings.gradle diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java b/src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java rename to src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java b/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java rename to src/main/java/codzilla/backend/authservice/AdminController/AdminController.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java b/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java rename to src/main/java/codzilla/backend/authservice/AuthController/AuthController.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java b/src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java rename to src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/AuthServiceApplication.java b/src/main/java/codzilla/backend/authservice/AuthServiceApplication.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/AuthServiceApplication.java rename to src/main/java/codzilla/backend/authservice/AuthServiceApplication.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/RestException.java b/src/main/java/codzilla/backend/authservice/Exceptions/RestException.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/Exceptions/RestException.java rename to src/main/java/codzilla/backend/authservice/Exceptions/RestException.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java b/src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java rename to src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java b/src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java rename to src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java b/src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java rename to src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java b/src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java rename to src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java b/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java rename to src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java b/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java rename to src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/Repository/UserRepository.java b/src/main/java/codzilla/backend/authservice/Repository/UserRepository.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/Repository/UserRepository.java rename to src/main/java/codzilla/backend/authservice/Repository/UserRepository.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java b/src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java rename to src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java b/src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java rename to src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/User.java b/src/main/java/codzilla/backend/authservice/User.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/User.java rename to src/main/java/codzilla/backend/authservice/User.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/UserService.java b/src/main/java/codzilla/backend/authservice/UserService.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/UserService.java rename to src/main/java/codzilla/backend/authservice/UserService.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java b/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java rename to src/main/java/codzilla/backend/authservice/ViewController/ViewController.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/PasswordConfig.java b/src/main/java/codzilla/backend/authservice/config/PasswordConfig.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/config/PasswordConfig.java rename to src/main/java/codzilla/backend/authservice/config/PasswordConfig.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/RedisConfig.java b/src/main/java/codzilla/backend/authservice/config/RedisConfig.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/config/RedisConfig.java rename to src/main/java/codzilla/backend/authservice/config/RedisConfig.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java b/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java rename to src/main/java/codzilla/backend/authservice/config/SecurityConfig.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/config/Settings.java b/src/main/java/codzilla/backend/authservice/config/Settings.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/config/Settings.java rename to src/main/java/codzilla/backend/authservice/config/Settings.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java b/src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java rename to src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java b/src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java rename to src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java b/src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java rename to src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java b/src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java rename to src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java b/src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java rename to src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java diff --git a/AuthService/src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java b/src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java similarity index 100% rename from AuthService/src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java rename to src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java diff --git a/AuthService/src/main/resources/application.properties b/src/main/resources/application.properties similarity index 100% rename from AuthService/src/main/resources/application.properties rename to src/main/resources/application.properties diff --git a/AuthService/src/main/resources/static/login.html b/src/main/resources/static/login.html similarity index 100% rename from AuthService/src/main/resources/static/login.html rename to src/main/resources/static/login.html diff --git a/AuthService/src/main/resources/static/signup.html b/src/main/resources/static/signup.html similarity index 100% rename from AuthService/src/main/resources/static/signup.html rename to src/main/resources/static/signup.html diff --git a/AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java b/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java similarity index 100% rename from AuthService/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java rename to src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java diff --git a/AuthService/src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java b/src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java similarity index 100% rename from AuthService/src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java rename to src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java diff --git a/AuthService/src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java b/src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java similarity index 100% rename from AuthService/src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java rename to src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java diff --git a/AuthService/src/test/resources/application.properties b/src/test/resources/application.properties similarity index 100% rename from AuthService/src/test/resources/application.properties rename to src/test/resources/application.properties From c390ba0b9ac715363345975fcd215f86a177cd5c Mon Sep 17 00:00:00 2001 From: toximu Date: Wed, 11 Mar 2026 11:37:45 +0300 Subject: [PATCH 06/11] rename project --- .../backend}/AdminAccessDeniedHandler.java | 2 +- .../AdminController/AdminController.java | 4 ++-- .../AuthController/AuthController.java | 24 ++++++++----------- .../backend}/AuthExceptionHandler.java | 13 +++------- .../backend}/AuthServiceApplication.java | 2 +- .../backend}/Exceptions/RestException.java | 2 +- .../UserAlreadyExistsException.java | 2 +- .../Exceptions/UserNotFoundException.java | 2 +- .../Exceptions/UsernameIsTakenException.java | 2 +- .../backend}/HttpStatusEntryPoint.java | 2 +- .../JWTRequestFilter/JWTRequestFilter.java | 4 ++-- .../codzilla/backend}/JWTUtils/JWTUtils.java | 4 ++-- .../backend}/Repository/UserRepository.java | 4 ++-- .../RepositoryUserDetailsService.java | 4 ++-- .../SimpleController/SimpleController.java | 2 +- .../codzilla/backend}/User.java | 2 +- .../codzilla/backend}/UserService.java | 16 ++++++------- .../ViewController/ViewController.java | 2 +- .../backend}/config/PasswordConfig.java | 2 +- .../codzilla/backend}/config/RedisConfig.java | 2 +- .../backend}/config/SecurityConfig.java | 14 ++++------- .../codzilla/backend}/config/Settings.java | 2 +- .../backend}/dto/ErrorResponseDTO.java | 4 ++-- .../backend}/dto/LoginRequestDTO.java | 2 +- .../backend}/dto/LoginResponseDTO.java | 2 +- .../backend}/dto/RegisterRequestDTO.java | 2 +- .../backend}/dto/RegisterResponseDTO.java | 2 +- .../backend}/dto/UserResponseDTO.java | 2 +- src/main/resources/application.properties | 2 -- .../backend}/AuthServiceApplicationTests.java | 2 +- .../backend}/BaseIntegrationTest.java | 4 ++-- .../backend}/RegisterIntegrationTest.java | 10 ++++---- 32 files changed, 62 insertions(+), 83 deletions(-) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/AdminAccessDeniedHandler.java (95%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/AdminController/AdminController.java (88%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/AuthController/AuthController.java (87%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/AuthExceptionHandler.java (71%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/AuthServiceApplication.java (88%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/Exceptions/RestException.java (84%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/Exceptions/UserAlreadyExistsException.java (81%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/Exceptions/UserNotFoundException.java (80%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/Exceptions/UsernameIsTakenException.java (81%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/HttpStatusEntryPoint.java (95%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/JWTRequestFilter/JWTRequestFilter.java (95%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/JWTUtils/JWTUtils.java (95%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/Repository/UserRepository.java (76%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/RepositoryUserDetailsService.java (89%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/SimpleController/SimpleController.java (86%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/User.java (97%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/UserService.java (82%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/ViewController/ViewController.java (86%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/config/PasswordConfig.java (89%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/config/RedisConfig.java (95%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/config/SecurityConfig.java (83%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/config/Settings.java (89%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/dto/ErrorResponseDTO.java (74%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/dto/LoginRequestDTO.java (67%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/dto/LoginResponseDTO.java (60%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/dto/RegisterRequestDTO.java (73%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/dto/RegisterResponseDTO.java (61%) rename src/main/java/{codzilla/backend/authservice => com/codzilla/backend}/dto/UserResponseDTO.java (79%) rename src/test/java/{codzilla/backend/authservice => com/codzilla/backend}/AuthServiceApplicationTests.java (85%) rename src/test/java/{codzilla/backend/authservice => com/codzilla/backend}/BaseIntegrationTest.java (86%) rename src/test/java/{codzilla/backend/authservice => com/codzilla/backend}/RegisterIntegrationTest.java (90%) diff --git a/src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java b/src/main/java/com/codzilla/backend/AdminAccessDeniedHandler.java similarity index 95% rename from src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java rename to src/main/java/com/codzilla/backend/AdminAccessDeniedHandler.java index b15c1af..e02715f 100644 --- a/src/main/java/codzilla/backend/authservice/AdminAccessDeniedHandler.java +++ b/src/main/java/com/codzilla/backend/AdminAccessDeniedHandler.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; import jakarta.servlet.http.HttpServletRequest; diff --git a/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java b/src/main/java/com/codzilla/backend/AdminController/AdminController.java similarity index 88% rename from src/main/java/codzilla/backend/authservice/AdminController/AdminController.java rename to src/main/java/com/codzilla/backend/AdminController/AdminController.java index 9086765..186d9d9 100644 --- a/src/main/java/codzilla/backend/authservice/AdminController/AdminController.java +++ b/src/main/java/com/codzilla/backend/AdminController/AdminController.java @@ -1,6 +1,6 @@ -package codzilla.backend.authservice.AdminController; +package com.codzilla.backend.AdminController; -import codzilla.backend.authservice.UserService; +import com.codzilla.backend.UserService; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java b/src/main/java/com/codzilla/backend/AuthController/AuthController.java similarity index 87% rename from src/main/java/codzilla/backend/authservice/AuthController/AuthController.java rename to src/main/java/com/codzilla/backend/AuthController/AuthController.java index ae5b41b..48c8aa9 100644 --- a/src/main/java/codzilla/backend/authservice/AuthController/AuthController.java +++ b/src/main/java/com/codzilla/backend/AuthController/AuthController.java @@ -1,13 +1,13 @@ -package codzilla.backend.authservice.AuthController; - -import codzilla.backend.authservice.JWTUtils.JWTUtils; -import codzilla.backend.authservice.User; -import codzilla.backend.authservice.UserService; -import codzilla.backend.authservice.config.Settings; -import codzilla.backend.authservice.dto.LoginRequestDTO; -import codzilla.backend.authservice.dto.LoginResponseDTO; -import codzilla.backend.authservice.dto.RegisterRequestDTO; -import codzilla.backend.authservice.dto.RegisterResponseDTO; +package com.codzilla.backend.AuthController; + +import com.codzilla.backend.JWTUtils.JWTUtils; +import com.codzilla.backend.User; +import com.codzilla.backend.UserService; +import com.codzilla.backend.config.Settings; +import com.codzilla.backend.dto.LoginRequestDTO; +import com.codzilla.backend.dto.LoginResponseDTO; +import com.codzilla.backend.dto.RegisterRequestDTO; +import com.codzilla.backend.dto.RegisterResponseDTO; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -19,12 +19,8 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; import org.springframework.web.bind.annotation.*; -import java.util.Map; - @Slf4j @RestController @RequestMapping("/auth") diff --git a/src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java b/src/main/java/com/codzilla/backend/AuthExceptionHandler.java similarity index 71% rename from src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java rename to src/main/java/com/codzilla/backend/AuthExceptionHandler.java index e22b3b6..d49c63b 100644 --- a/src/main/java/codzilla/backend/authservice/AuthExceptionHandler.java +++ b/src/main/java/com/codzilla/backend/AuthExceptionHandler.java @@ -1,11 +1,7 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; -import codzilla.backend.authservice.Exceptions.RestException; -import codzilla.backend.authservice.Exceptions.UserAlreadyExistsException; -import codzilla.backend.authservice.Exceptions.UserNotFoundException; -import codzilla.backend.authservice.Exceptions.UsernameIsTakenException; -import codzilla.backend.authservice.dto.ErrorResponseDTO; -import org.apache.coyote.BadRequestException; +import com.codzilla.backend.Exceptions.RestException; +import com.codzilla.backend.dto.ErrorResponseDTO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -14,9 +10,6 @@ import org.springframework.web.bind.annotation.RestControllerAdvice; import tools.jackson.databind.ObjectMapper; -import java.util.HashMap; -import java.util.Map; - @RestControllerAdvice public class AuthExceptionHandler { @Autowired diff --git a/src/main/java/codzilla/backend/authservice/AuthServiceApplication.java b/src/main/java/com/codzilla/backend/AuthServiceApplication.java similarity index 88% rename from src/main/java/codzilla/backend/authservice/AuthServiceApplication.java rename to src/main/java/com/codzilla/backend/AuthServiceApplication.java index bed022d..38268b8 100644 --- a/src/main/java/codzilla/backend/authservice/AuthServiceApplication.java +++ b/src/main/java/com/codzilla/backend/AuthServiceApplication.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/src/main/java/codzilla/backend/authservice/Exceptions/RestException.java b/src/main/java/com/codzilla/backend/Exceptions/RestException.java similarity index 84% rename from src/main/java/codzilla/backend/authservice/Exceptions/RestException.java rename to src/main/java/com/codzilla/backend/Exceptions/RestException.java index 8c7ea37..91f8699 100644 --- a/src/main/java/codzilla/backend/authservice/Exceptions/RestException.java +++ b/src/main/java/com/codzilla/backend/Exceptions/RestException.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.Exceptions; +package com.codzilla.backend.Exceptions; import lombok.Data; import org.springframework.http.HttpStatus; diff --git a/src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java b/src/main/java/com/codzilla/backend/Exceptions/UserAlreadyExistsException.java similarity index 81% rename from src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java rename to src/main/java/com/codzilla/backend/Exceptions/UserAlreadyExistsException.java index 1e727d1..8f05b54 100644 --- a/src/main/java/codzilla/backend/authservice/Exceptions/UserAlreadyExistsException.java +++ b/src/main/java/com/codzilla/backend/Exceptions/UserAlreadyExistsException.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.Exceptions; +package com.codzilla.backend.Exceptions; import org.springframework.http.HttpStatus; diff --git a/src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java b/src/main/java/com/codzilla/backend/Exceptions/UserNotFoundException.java similarity index 80% rename from src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java rename to src/main/java/com/codzilla/backend/Exceptions/UserNotFoundException.java index a044152..a054e8d 100644 --- a/src/main/java/codzilla/backend/authservice/Exceptions/UserNotFoundException.java +++ b/src/main/java/com/codzilla/backend/Exceptions/UserNotFoundException.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.Exceptions; +package com.codzilla.backend.Exceptions; import org.springframework.http.HttpStatus; diff --git a/src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java b/src/main/java/com/codzilla/backend/Exceptions/UsernameIsTakenException.java similarity index 81% rename from src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java rename to src/main/java/com/codzilla/backend/Exceptions/UsernameIsTakenException.java index c1d79a5..e503c01 100644 --- a/src/main/java/codzilla/backend/authservice/Exceptions/UsernameIsTakenException.java +++ b/src/main/java/com/codzilla/backend/Exceptions/UsernameIsTakenException.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.Exceptions; +package com.codzilla.backend.Exceptions; import org.springframework.http.HttpStatus; diff --git a/src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java b/src/main/java/com/codzilla/backend/HttpStatusEntryPoint.java similarity index 95% rename from src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java rename to src/main/java/com/codzilla/backend/HttpStatusEntryPoint.java index 4031ea8..bc21093 100644 --- a/src/main/java/codzilla/backend/authservice/HttpStatusEntryPoint.java +++ b/src/main/java/com/codzilla/backend/HttpStatusEntryPoint.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java b/src/main/java/com/codzilla/backend/JWTRequestFilter/JWTRequestFilter.java similarity index 95% rename from src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java rename to src/main/java/com/codzilla/backend/JWTRequestFilter/JWTRequestFilter.java index a958118..e92ac9f 100644 --- a/src/main/java/codzilla/backend/authservice/JWTRequestFilter/JWTRequestFilter.java +++ b/src/main/java/com/codzilla/backend/JWTRequestFilter/JWTRequestFilter.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.JWTRequestFilter; +package com.codzilla.backend.JWTRequestFilter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -14,7 +14,7 @@ import java.io.IOException; import java.util.List; -import codzilla.backend.authservice.JWTUtils.JWTUtils; +import com.codzilla.backend.JWTUtils.JWTUtils; @Slf4j @Component diff --git a/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java b/src/main/java/com/codzilla/backend/JWTUtils/JWTUtils.java similarity index 95% rename from src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java rename to src/main/java/com/codzilla/backend/JWTUtils/JWTUtils.java index bfef082..47da3ed 100644 --- a/src/main/java/codzilla/backend/authservice/JWTUtils/JWTUtils.java +++ b/src/main/java/com/codzilla/backend/JWTUtils/JWTUtils.java @@ -1,6 +1,6 @@ -package codzilla.backend.authservice.JWTUtils; +package com.codzilla.backend.JWTUtils; -import codzilla.backend.authservice.config.Settings; +import com.codzilla.backend.config.Settings; import io.jsonwebtoken.*; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; diff --git a/src/main/java/codzilla/backend/authservice/Repository/UserRepository.java b/src/main/java/com/codzilla/backend/Repository/UserRepository.java similarity index 76% rename from src/main/java/codzilla/backend/authservice/Repository/UserRepository.java rename to src/main/java/com/codzilla/backend/Repository/UserRepository.java index 19a5d1c..9f91dff 100644 --- a/src/main/java/codzilla/backend/authservice/Repository/UserRepository.java +++ b/src/main/java/com/codzilla/backend/Repository/UserRepository.java @@ -1,6 +1,6 @@ -package codzilla.backend.authservice.Repository; +package com.codzilla.backend.Repository; -import codzilla.backend.authservice.User; +import com.codzilla.backend.User; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; diff --git a/src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java b/src/main/java/com/codzilla/backend/RepositoryUserDetailsService.java similarity index 89% rename from src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java rename to src/main/java/com/codzilla/backend/RepositoryUserDetailsService.java index 8333e85..df9d759 100644 --- a/src/main/java/codzilla/backend/authservice/RepositoryUserDetailsService.java +++ b/src/main/java/com/codzilla/backend/RepositoryUserDetailsService.java @@ -1,6 +1,6 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; -import codzilla.backend.authservice.Repository.UserRepository; +import com.codzilla.backend.Repository.UserRepository; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; diff --git a/src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java b/src/main/java/com/codzilla/backend/SimpleController/SimpleController.java similarity index 86% rename from src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java rename to src/main/java/com/codzilla/backend/SimpleController/SimpleController.java index 62f9874..05126c0 100644 --- a/src/main/java/codzilla/backend/authservice/SimpleController/SimpleController.java +++ b/src/main/java/com/codzilla/backend/SimpleController/SimpleController.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.SimpleController; +package com.codzilla.backend.SimpleController; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/codzilla/backend/authservice/User.java b/src/main/java/com/codzilla/backend/User.java similarity index 97% rename from src/main/java/codzilla/backend/authservice/User.java rename to src/main/java/com/codzilla/backend/User.java index 83d6c0d..b74cdba 100644 --- a/src/main/java/codzilla/backend/authservice/User.java +++ b/src/main/java/com/codzilla/backend/User.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; import jakarta.persistence.*; import lombok.AllArgsConstructor; diff --git a/src/main/java/codzilla/backend/authservice/UserService.java b/src/main/java/com/codzilla/backend/UserService.java similarity index 82% rename from src/main/java/codzilla/backend/authservice/UserService.java rename to src/main/java/com/codzilla/backend/UserService.java index 4d7e509..f066ca4 100644 --- a/src/main/java/codzilla/backend/authservice/UserService.java +++ b/src/main/java/com/codzilla/backend/UserService.java @@ -1,18 +1,16 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; -import codzilla.backend.authservice.Exceptions.UserAlreadyExistsException; -import codzilla.backend.authservice.Exceptions.UserNotFoundException; -import codzilla.backend.authservice.Exceptions.UsernameIsTakenException; -import codzilla.backend.authservice.Repository.UserRepository; -import codzilla.backend.authservice.dto.RegisterRequestDTO; -import codzilla.backend.authservice.dto.UserResponseDTO; -import org.springframework.http.HttpStatus; +import com.codzilla.backend.Exceptions.UserAlreadyExistsException; +import com.codzilla.backend.Exceptions.UserNotFoundException; +import com.codzilla.backend.Exceptions.UsernameIsTakenException; +import com.codzilla.backend.Repository.UserRepository; +import com.codzilla.backend.dto.RegisterRequestDTO; +import com.codzilla.backend.dto.UserResponseDTO; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; -import java.util.Collection; import java.util.List; @Service diff --git a/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java b/src/main/java/com/codzilla/backend/ViewController/ViewController.java similarity index 86% rename from src/main/java/codzilla/backend/authservice/ViewController/ViewController.java rename to src/main/java/com/codzilla/backend/ViewController/ViewController.java index 24e73be..845f48a 100644 --- a/src/main/java/codzilla/backend/authservice/ViewController/ViewController.java +++ b/src/main/java/com/codzilla/backend/ViewController/ViewController.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.ViewController; +package com.codzilla.backend.ViewController; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/codzilla/backend/authservice/config/PasswordConfig.java b/src/main/java/com/codzilla/backend/config/PasswordConfig.java similarity index 89% rename from src/main/java/codzilla/backend/authservice/config/PasswordConfig.java rename to src/main/java/com/codzilla/backend/config/PasswordConfig.java index ed1e5c4..cb1b728 100644 --- a/src/main/java/codzilla/backend/authservice/config/PasswordConfig.java +++ b/src/main/java/com/codzilla/backend/config/PasswordConfig.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.config; +package com.codzilla.backend.config; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/codzilla/backend/authservice/config/RedisConfig.java b/src/main/java/com/codzilla/backend/config/RedisConfig.java similarity index 95% rename from src/main/java/codzilla/backend/authservice/config/RedisConfig.java rename to src/main/java/com/codzilla/backend/config/RedisConfig.java index fd283fa..24eeb9c 100644 --- a/src/main/java/codzilla/backend/authservice/config/RedisConfig.java +++ b/src/main/java/com/codzilla/backend/config/RedisConfig.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.config; +package com.codzilla.backend.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java b/src/main/java/com/codzilla/backend/config/SecurityConfig.java similarity index 83% rename from src/main/java/codzilla/backend/authservice/config/SecurityConfig.java rename to src/main/java/com/codzilla/backend/config/SecurityConfig.java index de1d825..4802bbd 100644 --- a/src/main/java/codzilla/backend/authservice/config/SecurityConfig.java +++ b/src/main/java/com/codzilla/backend/config/SecurityConfig.java @@ -1,10 +1,8 @@ -package codzilla.backend.authservice.config; +package com.codzilla.backend.config; -import codzilla.backend.authservice.AdminAccessDeniedHandler; -import codzilla.backend.authservice.HttpStatusEntryPoint; -import codzilla.backend.authservice.JWTRequestFilter.JWTRequestFilter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; +import com.codzilla.backend.AdminAccessDeniedHandler; +import com.codzilla.backend.HttpStatusEntryPoint; +import com.codzilla.backend.JWTRequestFilter.JWTRequestFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; @@ -13,15 +11,11 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.access.AccessDeniedHandler; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.CorsConfigurationSource; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import tools.jackson.databind.ObjectMapper; import java.util.Arrays; -import java.util.List; @Configuration @EnableMethodSecurity diff --git a/src/main/java/codzilla/backend/authservice/config/Settings.java b/src/main/java/com/codzilla/backend/config/Settings.java similarity index 89% rename from src/main/java/codzilla/backend/authservice/config/Settings.java rename to src/main/java/com/codzilla/backend/config/Settings.java index b3c5292..26532a9 100644 --- a/src/main/java/codzilla/backend/authservice/config/Settings.java +++ b/src/main/java/com/codzilla/backend/config/Settings.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.config; +package com.codzilla.backend.config; import jakarta.annotation.PostConstruct; import lombok.Data; diff --git a/src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java b/src/main/java/com/codzilla/backend/dto/ErrorResponseDTO.java similarity index 74% rename from src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java rename to src/main/java/com/codzilla/backend/dto/ErrorResponseDTO.java index d45d318..feaaa9a 100644 --- a/src/main/java/codzilla/backend/authservice/dto/ErrorResponseDTO.java +++ b/src/main/java/com/codzilla/backend/dto/ErrorResponseDTO.java @@ -1,6 +1,6 @@ -package codzilla.backend.authservice.dto; +package com.codzilla.backend.dto; -import codzilla.backend.authservice.Exceptions.RestException; +import com.codzilla.backend.Exceptions.RestException; import org.springframework.http.HttpStatus; public record ErrorResponseDTO( diff --git a/src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java b/src/main/java/com/codzilla/backend/dto/LoginRequestDTO.java similarity index 67% rename from src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java rename to src/main/java/com/codzilla/backend/dto/LoginRequestDTO.java index 26f544d..f35a482 100644 --- a/src/main/java/codzilla/backend/authservice/dto/LoginRequestDTO.java +++ b/src/main/java/com/codzilla/backend/dto/LoginRequestDTO.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.dto; +package com.codzilla.backend.dto; public record LoginRequestDTO( String email, diff --git a/src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java b/src/main/java/com/codzilla/backend/dto/LoginResponseDTO.java similarity index 60% rename from src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java rename to src/main/java/com/codzilla/backend/dto/LoginResponseDTO.java index 8263dad..9c85b7c 100644 --- a/src/main/java/codzilla/backend/authservice/dto/LoginResponseDTO.java +++ b/src/main/java/com/codzilla/backend/dto/LoginResponseDTO.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.dto; +package com.codzilla.backend.dto; public record LoginResponseDTO( String username diff --git a/src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java b/src/main/java/com/codzilla/backend/dto/RegisterRequestDTO.java similarity index 73% rename from src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java rename to src/main/java/com/codzilla/backend/dto/RegisterRequestDTO.java index f942c35..4c29c78 100644 --- a/src/main/java/codzilla/backend/authservice/dto/RegisterRequestDTO.java +++ b/src/main/java/com/codzilla/backend/dto/RegisterRequestDTO.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.dto; +package com.codzilla.backend.dto; public record RegisterRequestDTO( String username, diff --git a/src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java b/src/main/java/com/codzilla/backend/dto/RegisterResponseDTO.java similarity index 61% rename from src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java rename to src/main/java/com/codzilla/backend/dto/RegisterResponseDTO.java index 21866d8..a28f59b 100644 --- a/src/main/java/codzilla/backend/authservice/dto/RegisterResponseDTO.java +++ b/src/main/java/com/codzilla/backend/dto/RegisterResponseDTO.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.dto; +package com.codzilla.backend.dto; public record RegisterResponseDTO( String username diff --git a/src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java b/src/main/java/com/codzilla/backend/dto/UserResponseDTO.java similarity index 79% rename from src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java rename to src/main/java/com/codzilla/backend/dto/UserResponseDTO.java index e8fe14d..825c80f 100644 --- a/src/main/java/codzilla/backend/authservice/dto/UserResponseDTO.java +++ b/src/main/java/com/codzilla/backend/dto/UserResponseDTO.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice.dto; +package com.codzilla.backend.dto; import java.util.List; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 6592970..80fd9af 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -6,5 +6,3 @@ spring.datasource.url=${DB_URL} spring.datasource.username=${DB_USERNAME} spring.datasource.password=${DB_PASSWORD} spring.jpa.hibernate.ddl-auto=update - -#logging.level.org.springframework.security=DEBUG \ No newline at end of file diff --git a/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java b/src/test/java/com/codzilla/backend/AuthServiceApplicationTests.java similarity index 85% rename from src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java rename to src/test/java/com/codzilla/backend/AuthServiceApplicationTests.java index 1b7a8e9..09b906d 100644 --- a/src/test/java/codzilla/backend/authservice/AuthServiceApplicationTests.java +++ b/src/test/java/com/codzilla/backend/AuthServiceApplicationTests.java @@ -1,4 +1,4 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; diff --git a/src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java b/src/test/java/com/codzilla/backend/BaseIntegrationTest.java similarity index 86% rename from src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java rename to src/test/java/com/codzilla/backend/BaseIntegrationTest.java index 872a156..a080c39 100644 --- a/src/test/java/codzilla/backend/authservice/BaseIntegrationTest.java +++ b/src/test/java/com/codzilla/backend/BaseIntegrationTest.java @@ -1,6 +1,6 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; -import codzilla.backend.authservice.Repository.UserRepository; +import com.codzilla.backend.Repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; diff --git a/src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java b/src/test/java/com/codzilla/backend/RegisterIntegrationTest.java similarity index 90% rename from src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java rename to src/test/java/com/codzilla/backend/RegisterIntegrationTest.java index c042526..d64513b 100644 --- a/src/test/java/codzilla/backend/authservice/RegisterIntegrationTest.java +++ b/src/test/java/com/codzilla/backend/RegisterIntegrationTest.java @@ -1,9 +1,9 @@ -package codzilla.backend.authservice; +package com.codzilla.backend; -import codzilla.backend.authservice.Exceptions.UserAlreadyExistsException; -import codzilla.backend.authservice.dto.ErrorResponseDTO; -import codzilla.backend.authservice.dto.RegisterRequestDTO; -import codzilla.backend.authservice.dto.RegisterResponseDTO; +import com.codzilla.backend.Exceptions.UserAlreadyExistsException; +import com.codzilla.backend.dto.ErrorResponseDTO; +import com.codzilla.backend.dto.RegisterRequestDTO; +import com.codzilla.backend.dto.RegisterResponseDTO; import jakarta.transaction.Transactional; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; From 1445caa5bc3c68821d0e360e3726b5a761a6dbe6 Mon Sep 17 00:00:00 2001 From: toximu Date: Wed, 11 Mar 2026 11:45:43 +0300 Subject: [PATCH 07/11] delete test html pages --- .../AdminController/AdminController.java | 30 ------- .../SimpleController/SimpleController.java | 15 ---- .../ViewController/ViewController.java | 19 ----- .../codzilla/backend/config/RedisConfig.java | 26 ------ .../backend/config/SecurityConfig.java | 4 +- src/main/resources/static/login.html | 81 ------------------- src/main/resources/static/signup.html | 69 ---------------- 7 files changed, 2 insertions(+), 242 deletions(-) delete mode 100644 src/main/java/com/codzilla/backend/AdminController/AdminController.java delete mode 100644 src/main/java/com/codzilla/backend/SimpleController/SimpleController.java delete mode 100644 src/main/java/com/codzilla/backend/ViewController/ViewController.java delete mode 100644 src/main/java/com/codzilla/backend/config/RedisConfig.java delete mode 100644 src/main/resources/static/login.html delete mode 100644 src/main/resources/static/signup.html diff --git a/src/main/java/com/codzilla/backend/AdminController/AdminController.java b/src/main/java/com/codzilla/backend/AdminController/AdminController.java deleted file mode 100644 index 186d9d9..0000000 --- a/src/main/java/com/codzilla/backend/AdminController/AdminController.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.codzilla.backend.AdminController; - -import com.codzilla.backend.UserService; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/admin") -@PreAuthorize("hasAuthority('ADMIN')") -public class AdminController { - - private final UserService userService; - - public AdminController(UserService userService) { - this.userService = userService; - } - - @GetMapping("/info") - String getAdminInfo() { - return "Some admin info."; - } - - @GetMapping("/users") - ResponseEntity getAllUsers() { - return ResponseEntity.ok(userService.getAllUsers()); - } -} diff --git a/src/main/java/com/codzilla/backend/SimpleController/SimpleController.java b/src/main/java/com/codzilla/backend/SimpleController/SimpleController.java deleted file mode 100644 index 05126c0..0000000 --- a/src/main/java/com/codzilla/backend/SimpleController/SimpleController.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.codzilla.backend.SimpleController; - - -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequestMapping("/simple") -public class SimpleController { - @GetMapping("/") - String getSomeInfo() { - return "Some common info."; - } -} diff --git a/src/main/java/com/codzilla/backend/ViewController/ViewController.java b/src/main/java/com/codzilla/backend/ViewController/ViewController.java deleted file mode 100644 index 845f48a..0000000 --- a/src/main/java/com/codzilla/backend/ViewController/ViewController.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.codzilla.backend.ViewController; - -import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.GetMapping; - -@Controller -public class ViewController { - @GetMapping("/login") - public String getLoginPage() { - return "login.html"; - } - - @GetMapping("/signup") - public String getSignUpPage() { - return "signup.html"; - } - -} - diff --git a/src/main/java/com/codzilla/backend/config/RedisConfig.java b/src/main/java/com/codzilla/backend/config/RedisConfig.java deleted file mode 100644 index 24eeb9c..0000000 --- a/src/main/java/com/codzilla/backend/config/RedisConfig.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.codzilla.backend.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.connection.RedisConnectionFactory; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.serializer.StringRedisSerializer; - -@Configuration -public class RedisConfig { - - @Bean - public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory) { - RedisTemplate template = new RedisTemplate<>(); - template.setConnectionFactory(connectionFactory); - - template.setKeySerializer(new StringRedisSerializer()); - - template.setValueSerializer(new StringRedisSerializer()); - - template.setHashKeySerializer(new StringRedisSerializer()); - template.setHashValueSerializer(new StringRedisSerializer()); - - return template; - } -} diff --git a/src/main/java/com/codzilla/backend/config/SecurityConfig.java b/src/main/java/com/codzilla/backend/config/SecurityConfig.java index 4802bbd..4f04847 100644 --- a/src/main/java/com/codzilla/backend/config/SecurityConfig.java +++ b/src/main/java/com/codzilla/backend/config/SecurityConfig.java @@ -21,7 +21,7 @@ @EnableMethodSecurity public class SecurityConfig { - private static final String[] WHITELIST = {"/auth/**", "/login", "/login.html", "/signup", "/signup.html"}; + private static final String[] WHITELIST = {"/auth/**"}; private final HttpStatusEntryPoint unauthorizedHandler; @@ -37,7 +37,7 @@ public SecurityFilterChain filterChain(HttpSecurity http, JWTRequestFilter filte return http .cors(cors -> cors.configurationSource(request -> { CorsConfiguration config = new CorsConfiguration(); - config.setAllowedOrigins(Arrays.asList("http://localhost:5173")); // Твой порт Vite + config.setAllowedOrigins(Arrays.asList("http://localhost:5173")); config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); config.setAllowedHeaders(Arrays.asList("*")); config.setAllowCredentials(true); diff --git a/src/main/resources/static/login.html b/src/main/resources/static/login.html deleted file mode 100644 index dcad533..0000000 --- a/src/main/resources/static/login.html +++ /dev/null @@ -1,81 +0,0 @@ - - - - - Login - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/static/signup.html b/src/main/resources/static/signup.html deleted file mode 100644 index c791cf7..0000000 --- a/src/main/resources/static/signup.html +++ /dev/null @@ -1,69 +0,0 @@ - - - - - Регистрация - - - - -
-

Создать аккаунт

- - - - -

-

Уже есть аккаунт? Войти

-
- - - - - \ No newline at end of file From ff0dcf0895570ae57ad0001346e6905613caf6cb Mon Sep 17 00:00:00 2001 From: toximu Date: Wed, 11 Mar 2026 12:49:31 +0300 Subject: [PATCH 08/11] resolve dependencies --- build.gradle | 13 +++--------- .../backend/AuthServiceApplication.java | 13 ------------ .../{ => auth}/AdminAccessDeniedHandler.java | 2 +- .../AuthController/AuthController.java | 20 +++++++++---------- .../{ => auth}/AuthExceptionHandler.java | 6 +++--- .../{ => auth}/Exceptions/RestException.java | 2 +- .../UserAlreadyExistsException.java | 2 +- .../Exceptions/UserNotFoundException.java | 2 +- .../Exceptions/UsernameIsTakenException.java | 2 +- .../{ => auth}/HttpStatusEntryPoint.java | 2 +- .../JWTRequestFilter/JWTRequestFilter.java | 4 ++-- .../backend/{ => auth}/JWTUtils/JWTUtils.java | 4 ++-- .../{ => auth}/Repository/UserRepository.java | 4 ++-- .../RepositoryUserDetailsService.java | 4 ++-- .../com/codzilla/backend/{ => auth}/User.java | 4 +--- .../backend/{ => auth}/UserService.java | 14 ++++++------- .../{ => auth}/config/PasswordConfig.java | 2 +- .../{ => auth}/config/SecurityConfig.java | 8 ++++---- .../backend/{ => auth}/config/Settings.java | 3 +-- .../{ => auth}/dto/ErrorResponseDTO.java | 4 ++-- .../{ => auth}/dto/LoginRequestDTO.java | 2 +- .../{ => auth}/dto/LoginResponseDTO.java | 2 +- .../{ => auth}/dto/RegisterRequestDTO.java | 2 +- .../{ => auth}/dto/RegisterResponseDTO.java | 2 +- .../{ => auth}/dto/UserResponseDTO.java | 2 +- .../codzilla/backend/BaseIntegrationTest.java | 2 +- .../backend/RegisterIntegrationTest.java | 9 +++++---- .../controller/CoffeeControllerTest.java | 5 ++++- 28 files changed, 61 insertions(+), 80 deletions(-) delete mode 100644 src/main/java/com/codzilla/backend/AuthServiceApplication.java rename src/main/java/com/codzilla/backend/{ => auth}/AdminAccessDeniedHandler.java (96%) rename src/main/java/com/codzilla/backend/{ => auth}/AuthController/AuthController.java (91%) rename src/main/java/com/codzilla/backend/{ => auth}/AuthExceptionHandler.java (89%) rename src/main/java/com/codzilla/backend/{ => auth}/Exceptions/RestException.java (85%) rename src/main/java/com/codzilla/backend/{ => auth}/Exceptions/UserAlreadyExistsException.java (82%) rename src/main/java/com/codzilla/backend/{ => auth}/Exceptions/UserNotFoundException.java (81%) rename src/main/java/com/codzilla/backend/{ => auth}/Exceptions/UsernameIsTakenException.java (82%) rename src/main/java/com/codzilla/backend/{ => auth}/HttpStatusEntryPoint.java (95%) rename src/main/java/com/codzilla/backend/{ => auth}/JWTRequestFilter/JWTRequestFilter.java (95%) rename src/main/java/com/codzilla/backend/{ => auth}/JWTUtils/JWTUtils.java (96%) rename src/main/java/com/codzilla/backend/{ => auth}/Repository/UserRepository.java (77%) rename src/main/java/com/codzilla/backend/{ => auth}/RepositoryUserDetailsService.java (90%) rename src/main/java/com/codzilla/backend/{ => auth}/User.java (89%) rename src/main/java/com/codzilla/backend/{ => auth}/UserService.java (85%) rename src/main/java/com/codzilla/backend/{ => auth}/config/PasswordConfig.java (90%) rename src/main/java/com/codzilla/backend/{ => auth}/config/SecurityConfig.java (92%) rename src/main/java/com/codzilla/backend/{ => auth}/config/Settings.java (82%) rename src/main/java/com/codzilla/backend/{ => auth}/dto/ErrorResponseDTO.java (75%) rename src/main/java/com/codzilla/backend/{ => auth}/dto/LoginRequestDTO.java (69%) rename src/main/java/com/codzilla/backend/{ => auth}/dto/LoginResponseDTO.java (61%) rename src/main/java/com/codzilla/backend/{ => auth}/dto/RegisterRequestDTO.java (74%) rename src/main/java/com/codzilla/backend/{ => auth}/dto/RegisterResponseDTO.java (62%) rename src/main/java/com/codzilla/backend/{ => auth}/dto/UserResponseDTO.java (80%) diff --git a/build.gradle b/build.gradle index ed50507..74d3a57 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id 'java' - id 'org.springframework.boot' version '3.3.8' + id 'org.springframework.boot' version '4.0.3' id 'io.spring.dependency-management' version '1.1.7' } @@ -10,7 +10,7 @@ description = 'Backend' java { toolchain { - languageVersion = JavaLanguageVersion.of(21) + languageVersion = JavaLanguageVersion.of(23) } } @@ -21,7 +21,6 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-webmvc' - implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' runtimeOnly 'org.postgresql:postgresql' compileOnly 'org.projectlombok:lombok' @@ -36,15 +35,9 @@ dependencies { runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-data-jpa' - + testImplementation 'org.springframework.boot:spring-boot-starter-restclient-test' developmentOnly 'org.springframework.boot:spring-boot-devtools' - runtimeOnly 'org.postgresql:postgresql' - - testRuntimeOnly 'com.h2database:h2' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } tasks.named('test') { diff --git a/src/main/java/com/codzilla/backend/AuthServiceApplication.java b/src/main/java/com/codzilla/backend/AuthServiceApplication.java deleted file mode 100644 index 38268b8..0000000 --- a/src/main/java/com/codzilla/backend/AuthServiceApplication.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.codzilla.backend; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -public class AuthServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(AuthServiceApplication.class, args); - } - -} diff --git a/src/main/java/com/codzilla/backend/AdminAccessDeniedHandler.java b/src/main/java/com/codzilla/backend/auth/AdminAccessDeniedHandler.java similarity index 96% rename from src/main/java/com/codzilla/backend/AdminAccessDeniedHandler.java rename to src/main/java/com/codzilla/backend/auth/AdminAccessDeniedHandler.java index e02715f..a583451 100644 --- a/src/main/java/com/codzilla/backend/AdminAccessDeniedHandler.java +++ b/src/main/java/com/codzilla/backend/auth/AdminAccessDeniedHandler.java @@ -1,4 +1,4 @@ -package com.codzilla.backend; +package com.codzilla.backend.auth; import jakarta.servlet.http.HttpServletRequest; diff --git a/src/main/java/com/codzilla/backend/AuthController/AuthController.java b/src/main/java/com/codzilla/backend/auth/AuthController/AuthController.java similarity index 91% rename from src/main/java/com/codzilla/backend/AuthController/AuthController.java rename to src/main/java/com/codzilla/backend/auth/AuthController/AuthController.java index 48c8aa9..b63f1c1 100644 --- a/src/main/java/com/codzilla/backend/AuthController/AuthController.java +++ b/src/main/java/com/codzilla/backend/auth/AuthController/AuthController.java @@ -1,13 +1,13 @@ -package com.codzilla.backend.AuthController; - -import com.codzilla.backend.JWTUtils.JWTUtils; -import com.codzilla.backend.User; -import com.codzilla.backend.UserService; -import com.codzilla.backend.config.Settings; -import com.codzilla.backend.dto.LoginRequestDTO; -import com.codzilla.backend.dto.LoginResponseDTO; -import com.codzilla.backend.dto.RegisterRequestDTO; -import com.codzilla.backend.dto.RegisterResponseDTO; +package com.codzilla.backend.auth.AuthController; + +import com.codzilla.backend.auth.JWTUtils.JWTUtils; +import com.codzilla.backend.auth.User; +import com.codzilla.backend.auth.UserService; +import com.codzilla.backend.auth.config.Settings; +import com.codzilla.backend.auth.dto.LoginRequestDTO; +import com.codzilla.backend.auth.dto.LoginResponseDTO; +import com.codzilla.backend.auth.dto.RegisterRequestDTO; +import com.codzilla.backend.auth.dto.RegisterResponseDTO; import jakarta.servlet.http.Cookie; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/src/main/java/com/codzilla/backend/AuthExceptionHandler.java b/src/main/java/com/codzilla/backend/auth/AuthExceptionHandler.java similarity index 89% rename from src/main/java/com/codzilla/backend/AuthExceptionHandler.java rename to src/main/java/com/codzilla/backend/auth/AuthExceptionHandler.java index d49c63b..e6daa8c 100644 --- a/src/main/java/com/codzilla/backend/AuthExceptionHandler.java +++ b/src/main/java/com/codzilla/backend/auth/AuthExceptionHandler.java @@ -1,7 +1,7 @@ -package com.codzilla.backend; +package com.codzilla.backend.auth; -import com.codzilla.backend.Exceptions.RestException; -import com.codzilla.backend.dto.ErrorResponseDTO; +import com.codzilla.backend.auth.Exceptions.RestException; +import com.codzilla.backend.auth.dto.ErrorResponseDTO; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/com/codzilla/backend/Exceptions/RestException.java b/src/main/java/com/codzilla/backend/auth/Exceptions/RestException.java similarity index 85% rename from src/main/java/com/codzilla/backend/Exceptions/RestException.java rename to src/main/java/com/codzilla/backend/auth/Exceptions/RestException.java index 91f8699..9dfba70 100644 --- a/src/main/java/com/codzilla/backend/Exceptions/RestException.java +++ b/src/main/java/com/codzilla/backend/auth/Exceptions/RestException.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.Exceptions; +package com.codzilla.backend.auth.Exceptions; import lombok.Data; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/codzilla/backend/Exceptions/UserAlreadyExistsException.java b/src/main/java/com/codzilla/backend/auth/Exceptions/UserAlreadyExistsException.java similarity index 82% rename from src/main/java/com/codzilla/backend/Exceptions/UserAlreadyExistsException.java rename to src/main/java/com/codzilla/backend/auth/Exceptions/UserAlreadyExistsException.java index 8f05b54..3017e3d 100644 --- a/src/main/java/com/codzilla/backend/Exceptions/UserAlreadyExistsException.java +++ b/src/main/java/com/codzilla/backend/auth/Exceptions/UserAlreadyExistsException.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.Exceptions; +package com.codzilla.backend.auth.Exceptions; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/codzilla/backend/Exceptions/UserNotFoundException.java b/src/main/java/com/codzilla/backend/auth/Exceptions/UserNotFoundException.java similarity index 81% rename from src/main/java/com/codzilla/backend/Exceptions/UserNotFoundException.java rename to src/main/java/com/codzilla/backend/auth/Exceptions/UserNotFoundException.java index a054e8d..a22ff43 100644 --- a/src/main/java/com/codzilla/backend/Exceptions/UserNotFoundException.java +++ b/src/main/java/com/codzilla/backend/auth/Exceptions/UserNotFoundException.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.Exceptions; +package com.codzilla.backend.auth.Exceptions; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/codzilla/backend/Exceptions/UsernameIsTakenException.java b/src/main/java/com/codzilla/backend/auth/Exceptions/UsernameIsTakenException.java similarity index 82% rename from src/main/java/com/codzilla/backend/Exceptions/UsernameIsTakenException.java rename to src/main/java/com/codzilla/backend/auth/Exceptions/UsernameIsTakenException.java index e503c01..c9ba336 100644 --- a/src/main/java/com/codzilla/backend/Exceptions/UsernameIsTakenException.java +++ b/src/main/java/com/codzilla/backend/auth/Exceptions/UsernameIsTakenException.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.Exceptions; +package com.codzilla.backend.auth.Exceptions; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/codzilla/backend/HttpStatusEntryPoint.java b/src/main/java/com/codzilla/backend/auth/HttpStatusEntryPoint.java similarity index 95% rename from src/main/java/com/codzilla/backend/HttpStatusEntryPoint.java rename to src/main/java/com/codzilla/backend/auth/HttpStatusEntryPoint.java index bc21093..bf3ebb9 100644 --- a/src/main/java/com/codzilla/backend/HttpStatusEntryPoint.java +++ b/src/main/java/com/codzilla/backend/auth/HttpStatusEntryPoint.java @@ -1,4 +1,4 @@ -package com.codzilla.backend; +package com.codzilla.backend.auth; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/src/main/java/com/codzilla/backend/JWTRequestFilter/JWTRequestFilter.java b/src/main/java/com/codzilla/backend/auth/JWTRequestFilter/JWTRequestFilter.java similarity index 95% rename from src/main/java/com/codzilla/backend/JWTRequestFilter/JWTRequestFilter.java rename to src/main/java/com/codzilla/backend/auth/JWTRequestFilter/JWTRequestFilter.java index e92ac9f..962276a 100644 --- a/src/main/java/com/codzilla/backend/JWTRequestFilter/JWTRequestFilter.java +++ b/src/main/java/com/codzilla/backend/auth/JWTRequestFilter/JWTRequestFilter.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.JWTRequestFilter; +package com.codzilla.backend.auth.JWTRequestFilter; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -14,7 +14,7 @@ import java.io.IOException; import java.util.List; -import com.codzilla.backend.JWTUtils.JWTUtils; +import com.codzilla.backend.auth.JWTUtils.JWTUtils; @Slf4j @Component diff --git a/src/main/java/com/codzilla/backend/JWTUtils/JWTUtils.java b/src/main/java/com/codzilla/backend/auth/JWTUtils/JWTUtils.java similarity index 96% rename from src/main/java/com/codzilla/backend/JWTUtils/JWTUtils.java rename to src/main/java/com/codzilla/backend/auth/JWTUtils/JWTUtils.java index 47da3ed..ce75f40 100644 --- a/src/main/java/com/codzilla/backend/JWTUtils/JWTUtils.java +++ b/src/main/java/com/codzilla/backend/auth/JWTUtils/JWTUtils.java @@ -1,6 +1,6 @@ -package com.codzilla.backend.JWTUtils; +package com.codzilla.backend.auth.JWTUtils; -import com.codzilla.backend.config.Settings; +import com.codzilla.backend.auth.config.Settings; import io.jsonwebtoken.*; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; diff --git a/src/main/java/com/codzilla/backend/Repository/UserRepository.java b/src/main/java/com/codzilla/backend/auth/Repository/UserRepository.java similarity index 77% rename from src/main/java/com/codzilla/backend/Repository/UserRepository.java rename to src/main/java/com/codzilla/backend/auth/Repository/UserRepository.java index 9f91dff..62c4f65 100644 --- a/src/main/java/com/codzilla/backend/Repository/UserRepository.java +++ b/src/main/java/com/codzilla/backend/auth/Repository/UserRepository.java @@ -1,6 +1,6 @@ -package com.codzilla.backend.Repository; +package com.codzilla.backend.auth.Repository; -import com.codzilla.backend.User; +import com.codzilla.backend.auth.User; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; diff --git a/src/main/java/com/codzilla/backend/RepositoryUserDetailsService.java b/src/main/java/com/codzilla/backend/auth/RepositoryUserDetailsService.java similarity index 90% rename from src/main/java/com/codzilla/backend/RepositoryUserDetailsService.java rename to src/main/java/com/codzilla/backend/auth/RepositoryUserDetailsService.java index df9d759..4284e93 100644 --- a/src/main/java/com/codzilla/backend/RepositoryUserDetailsService.java +++ b/src/main/java/com/codzilla/backend/auth/RepositoryUserDetailsService.java @@ -1,6 +1,6 @@ -package com.codzilla.backend; +package com.codzilla.backend.auth; -import com.codzilla.backend.Repository.UserRepository; +import com.codzilla.backend.auth.Repository.UserRepository; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; diff --git a/src/main/java/com/codzilla/backend/User.java b/src/main/java/com/codzilla/backend/auth/User.java similarity index 89% rename from src/main/java/com/codzilla/backend/User.java rename to src/main/java/com/codzilla/backend/auth/User.java index b74cdba..a5abfe4 100644 --- a/src/main/java/com/codzilla/backend/User.java +++ b/src/main/java/com/codzilla/backend/auth/User.java @@ -1,4 +1,4 @@ -package com.codzilla.backend; +package com.codzilla.backend.auth; import jakarta.persistence.*; import lombok.AllArgsConstructor; @@ -11,8 +11,6 @@ import org.springframework.security.core.authority.AuthorityUtils; 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.UsernameNotFoundException; import java.util.Collection; diff --git a/src/main/java/com/codzilla/backend/UserService.java b/src/main/java/com/codzilla/backend/auth/UserService.java similarity index 85% rename from src/main/java/com/codzilla/backend/UserService.java rename to src/main/java/com/codzilla/backend/auth/UserService.java index f066ca4..8b766a6 100644 --- a/src/main/java/com/codzilla/backend/UserService.java +++ b/src/main/java/com/codzilla/backend/auth/UserService.java @@ -1,11 +1,11 @@ -package com.codzilla.backend; +package com.codzilla.backend.auth; -import com.codzilla.backend.Exceptions.UserAlreadyExistsException; -import com.codzilla.backend.Exceptions.UserNotFoundException; -import com.codzilla.backend.Exceptions.UsernameIsTakenException; -import com.codzilla.backend.Repository.UserRepository; -import com.codzilla.backend.dto.RegisterRequestDTO; -import com.codzilla.backend.dto.UserResponseDTO; +import com.codzilla.backend.auth.Exceptions.UserAlreadyExistsException; +import com.codzilla.backend.auth.Exceptions.UserNotFoundException; +import com.codzilla.backend.auth.Exceptions.UsernameIsTakenException; +import com.codzilla.backend.auth.Repository.UserRepository; +import com.codzilla.backend.auth.dto.RegisterRequestDTO; +import com.codzilla.backend.auth.dto.UserResponseDTO; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.crypto.password.PasswordEncoder; diff --git a/src/main/java/com/codzilla/backend/config/PasswordConfig.java b/src/main/java/com/codzilla/backend/auth/config/PasswordConfig.java similarity index 90% rename from src/main/java/com/codzilla/backend/config/PasswordConfig.java rename to src/main/java/com/codzilla/backend/auth/config/PasswordConfig.java index cb1b728..1e60b7f 100644 --- a/src/main/java/com/codzilla/backend/config/PasswordConfig.java +++ b/src/main/java/com/codzilla/backend/auth/config/PasswordConfig.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.config; +package com.codzilla.backend.auth.config; import org.springframework.context.annotation.Bean; diff --git a/src/main/java/com/codzilla/backend/config/SecurityConfig.java b/src/main/java/com/codzilla/backend/auth/config/SecurityConfig.java similarity index 92% rename from src/main/java/com/codzilla/backend/config/SecurityConfig.java rename to src/main/java/com/codzilla/backend/auth/config/SecurityConfig.java index 4f04847..6c40d17 100644 --- a/src/main/java/com/codzilla/backend/config/SecurityConfig.java +++ b/src/main/java/com/codzilla/backend/auth/config/SecurityConfig.java @@ -1,8 +1,8 @@ -package com.codzilla.backend.config; +package com.codzilla.backend.auth.config; -import com.codzilla.backend.AdminAccessDeniedHandler; -import com.codzilla.backend.HttpStatusEntryPoint; -import com.codzilla.backend.JWTRequestFilter.JWTRequestFilter; +import com.codzilla.backend.auth.AdminAccessDeniedHandler; +import com.codzilla.backend.auth.HttpStatusEntryPoint; +import com.codzilla.backend.auth.JWTRequestFilter.JWTRequestFilter; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; diff --git a/src/main/java/com/codzilla/backend/config/Settings.java b/src/main/java/com/codzilla/backend/auth/config/Settings.java similarity index 82% rename from src/main/java/com/codzilla/backend/config/Settings.java rename to src/main/java/com/codzilla/backend/auth/config/Settings.java index 26532a9..80ee5a7 100644 --- a/src/main/java/com/codzilla/backend/config/Settings.java +++ b/src/main/java/com/codzilla/backend/auth/config/Settings.java @@ -1,6 +1,5 @@ -package com.codzilla.backend.config; +package com.codzilla.backend.auth.config; -import jakarta.annotation.PostConstruct; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/codzilla/backend/dto/ErrorResponseDTO.java b/src/main/java/com/codzilla/backend/auth/dto/ErrorResponseDTO.java similarity index 75% rename from src/main/java/com/codzilla/backend/dto/ErrorResponseDTO.java rename to src/main/java/com/codzilla/backend/auth/dto/ErrorResponseDTO.java index feaaa9a..bb3391d 100644 --- a/src/main/java/com/codzilla/backend/dto/ErrorResponseDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/ErrorResponseDTO.java @@ -1,6 +1,6 @@ -package com.codzilla.backend.dto; +package com.codzilla.backend.auth.dto; -import com.codzilla.backend.Exceptions.RestException; +import com.codzilla.backend.auth.Exceptions.RestException; import org.springframework.http.HttpStatus; public record ErrorResponseDTO( diff --git a/src/main/java/com/codzilla/backend/dto/LoginRequestDTO.java b/src/main/java/com/codzilla/backend/auth/dto/LoginRequestDTO.java similarity index 69% rename from src/main/java/com/codzilla/backend/dto/LoginRequestDTO.java rename to src/main/java/com/codzilla/backend/auth/dto/LoginRequestDTO.java index f35a482..a73ec03 100644 --- a/src/main/java/com/codzilla/backend/dto/LoginRequestDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/LoginRequestDTO.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.dto; +package com.codzilla.backend.auth.dto; public record LoginRequestDTO( String email, diff --git a/src/main/java/com/codzilla/backend/dto/LoginResponseDTO.java b/src/main/java/com/codzilla/backend/auth/dto/LoginResponseDTO.java similarity index 61% rename from src/main/java/com/codzilla/backend/dto/LoginResponseDTO.java rename to src/main/java/com/codzilla/backend/auth/dto/LoginResponseDTO.java index 9c85b7c..424b839 100644 --- a/src/main/java/com/codzilla/backend/dto/LoginResponseDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/LoginResponseDTO.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.dto; +package com.codzilla.backend.auth.dto; public record LoginResponseDTO( String username diff --git a/src/main/java/com/codzilla/backend/dto/RegisterRequestDTO.java b/src/main/java/com/codzilla/backend/auth/dto/RegisterRequestDTO.java similarity index 74% rename from src/main/java/com/codzilla/backend/dto/RegisterRequestDTO.java rename to src/main/java/com/codzilla/backend/auth/dto/RegisterRequestDTO.java index 4c29c78..de30c33 100644 --- a/src/main/java/com/codzilla/backend/dto/RegisterRequestDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/RegisterRequestDTO.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.dto; +package com.codzilla.backend.auth.dto; public record RegisterRequestDTO( String username, diff --git a/src/main/java/com/codzilla/backend/dto/RegisterResponseDTO.java b/src/main/java/com/codzilla/backend/auth/dto/RegisterResponseDTO.java similarity index 62% rename from src/main/java/com/codzilla/backend/dto/RegisterResponseDTO.java rename to src/main/java/com/codzilla/backend/auth/dto/RegisterResponseDTO.java index a28f59b..aa9a73f 100644 --- a/src/main/java/com/codzilla/backend/dto/RegisterResponseDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/RegisterResponseDTO.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.dto; +package com.codzilla.backend.auth.dto; public record RegisterResponseDTO( String username diff --git a/src/main/java/com/codzilla/backend/dto/UserResponseDTO.java b/src/main/java/com/codzilla/backend/auth/dto/UserResponseDTO.java similarity index 80% rename from src/main/java/com/codzilla/backend/dto/UserResponseDTO.java rename to src/main/java/com/codzilla/backend/auth/dto/UserResponseDTO.java index 825c80f..bccce3c 100644 --- a/src/main/java/com/codzilla/backend/dto/UserResponseDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/UserResponseDTO.java @@ -1,4 +1,4 @@ -package com.codzilla.backend.dto; +package com.codzilla.backend.auth.dto; import java.util.List; diff --git a/src/test/java/com/codzilla/backend/BaseIntegrationTest.java b/src/test/java/com/codzilla/backend/BaseIntegrationTest.java index a080c39..560f423 100644 --- a/src/test/java/com/codzilla/backend/BaseIntegrationTest.java +++ b/src/test/java/com/codzilla/backend/BaseIntegrationTest.java @@ -1,6 +1,6 @@ package com.codzilla.backend; -import com.codzilla.backend.Repository.UserRepository; +import com.codzilla.backend.auth.Repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; diff --git a/src/test/java/com/codzilla/backend/RegisterIntegrationTest.java b/src/test/java/com/codzilla/backend/RegisterIntegrationTest.java index d64513b..8781d7d 100644 --- a/src/test/java/com/codzilla/backend/RegisterIntegrationTest.java +++ b/src/test/java/com/codzilla/backend/RegisterIntegrationTest.java @@ -1,9 +1,10 @@ package com.codzilla.backend; -import com.codzilla.backend.Exceptions.UserAlreadyExistsException; -import com.codzilla.backend.dto.ErrorResponseDTO; -import com.codzilla.backend.dto.RegisterRequestDTO; -import com.codzilla.backend.dto.RegisterResponseDTO; +import com.codzilla.backend.auth.Exceptions.UserAlreadyExistsException; +import com.codzilla.backend.auth.User; +import com.codzilla.backend.auth.dto.ErrorResponseDTO; +import com.codzilla.backend.auth.dto.RegisterRequestDTO; +import com.codzilla.backend.auth.dto.RegisterResponseDTO; import jakarta.transaction.Transactional; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/com/codzilla/backend/controller/CoffeeControllerTest.java b/src/test/java/com/codzilla/backend/controller/CoffeeControllerTest.java index 7be3348..8460d86 100644 --- a/src/test/java/com/codzilla/backend/controller/CoffeeControllerTest.java +++ b/src/test/java/com/codzilla/backend/controller/CoffeeControllerTest.java @@ -5,14 +5,17 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.web.client.TestRestTemplate; +//import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.resttestclient.TestRestTemplate; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import static org.assertj.core.api.Assertions.assertThat; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureTestRestTemplate class CoffeeControllerTest { @Autowired From 609bba5f0fcdc72d3d3c1783091fb8228496925b Mon Sep 17 00:00:00 2001 From: toximu Date: Thu, 12 Mar 2026 01:17:36 +0300 Subject: [PATCH 09/11] add tests --- build.gradle | 6 +- .../com/codzilla/backend/ExampleEndpoint.java | 15 ++ .../auth/AdminController/AdminController.java | 30 ++++ .../auth/AuthController/AuthController.java | 7 +- .../backend/auth/JWTUtils/JWTUtils.java | 55 +++---- .../auth/Repository/UserRepository.java | 2 +- .../java/com/codzilla/backend/auth/User.java | 3 +- .../codzilla/backend/auth/UserService.java | 19 ++- .../backend/auth/config/SecurityConfig.java | 2 +- .../backend/auth/dto/LoginResponseDTO.java | 2 +- .../backend/auth/dto/RegisterRequestDTO.java | 2 +- .../backend/auth/dto/RegisterResponseDTO.java | 2 +- .../backend/auth/dto/UserResponseDTO.java | 2 +- .../codzilla/backend/controller/Coffee.java | 50 ------ .../backend/controller/DataLoader.java | 26 --- .../controller/RestApiDemoController.java | 85 ---------- .../backend/repository/CoffeeRepository.java | 7 - src/main/resources/application.properties | 7 +- .../backend/AuthServiceApplicationTests.java | 14 -- .../{ => auth}/BaseIntegrationTest.java | 2 +- .../backend/auth/JwtIntegrationTest.java | 149 ++++++++++++++++++ .../backend/auth/LoginIntegrationTest.java | 57 +++++++ .../{ => auth}/RegisterIntegrationTest.java | 5 +- .../auth/RoleAccessIntegrationTest.java | 100 ++++++++++++ .../controller/CoffeeControllerTest.java | 73 --------- 25 files changed, 411 insertions(+), 311 deletions(-) create mode 100644 src/main/java/com/codzilla/backend/ExampleEndpoint.java create mode 100644 src/main/java/com/codzilla/backend/auth/AdminController/AdminController.java delete mode 100644 src/main/java/com/codzilla/backend/controller/Coffee.java delete mode 100644 src/main/java/com/codzilla/backend/controller/DataLoader.java delete mode 100644 src/main/java/com/codzilla/backend/controller/RestApiDemoController.java delete mode 100644 src/main/java/com/codzilla/backend/repository/CoffeeRepository.java delete mode 100644 src/test/java/com/codzilla/backend/AuthServiceApplicationTests.java rename src/test/java/com/codzilla/backend/{ => auth}/BaseIntegrationTest.java (95%) create mode 100644 src/test/java/com/codzilla/backend/auth/JwtIntegrationTest.java create mode 100644 src/test/java/com/codzilla/backend/auth/LoginIntegrationTest.java rename src/test/java/com/codzilla/backend/{ => auth}/RegisterIntegrationTest.java (95%) create mode 100644 src/test/java/com/codzilla/backend/auth/RoleAccessIntegrationTest.java delete mode 100644 src/test/java/com/codzilla/backend/controller/CoffeeControllerTest.java diff --git a/build.gradle b/build.gradle index 74d3a57..be376b9 100644 --- a/build.gradle +++ b/build.gradle @@ -34,9 +34,9 @@ dependencies { implementation 'io.jsonwebtoken:jjwt-api:0.12.5' runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' - implementation 'org.springframework.boot:spring-boot-starter-web' - testImplementation 'org.springframework.boot:spring-boot-starter-restclient-test' - developmentOnly 'org.springframework.boot:spring-boot-devtools' +// implementation 'org.springframework.boot:spring-boot-starter-web' +// testImplementation 'org.springframework.boot:spring-boot-starter-restclient-test' +// developmentOnly 'org.springframework.boot:spring-boot-devtools' } diff --git a/src/main/java/com/codzilla/backend/ExampleEndpoint.java b/src/main/java/com/codzilla/backend/ExampleEndpoint.java new file mode 100644 index 0000000..bee7df9 --- /dev/null +++ b/src/main/java/com/codzilla/backend/ExampleEndpoint.java @@ -0,0 +1,15 @@ +package com.codzilla.backend; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +public class ExampleEndpoint { + @GetMapping("/endpoint") + public ResponseEntity> endpoint() { + return ResponseEntity.ok(Map.of("message", "info")); + } +} diff --git a/src/main/java/com/codzilla/backend/auth/AdminController/AdminController.java b/src/main/java/com/codzilla/backend/auth/AdminController/AdminController.java new file mode 100644 index 0000000..e8da761 --- /dev/null +++ b/src/main/java/com/codzilla/backend/auth/AdminController/AdminController.java @@ -0,0 +1,30 @@ +package com.codzilla.backend.auth.AdminController; + +import com.codzilla.backend.auth.UserService; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/admin") +@PreAuthorize("hasAuthority('ADMIN')") +public class AdminController { + + private final UserService userService; + + public AdminController(UserService userService) { + this.userService = userService; + } + + @GetMapping("/info") + String getAdminInfo() { + return "Some admin info."; + } + + @GetMapping("/users") + ResponseEntity getAllUsers() { + return ResponseEntity.ok(userService.getAllUsers()); + } +} diff --git a/src/main/java/com/codzilla/backend/auth/AuthController/AuthController.java b/src/main/java/com/codzilla/backend/auth/AuthController/AuthController.java index b63f1c1..20c056d 100644 --- a/src/main/java/com/codzilla/backend/auth/AuthController/AuthController.java +++ b/src/main/java/com/codzilla/backend/auth/AuthController/AuthController.java @@ -18,7 +18,6 @@ import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; -import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.*; @Slf4j @@ -63,8 +62,8 @@ public ResponseEntity login(@RequestBody LoginRequestDTO request, HttpServlet refreshCookie.setSecure(false); response.addCookie(refreshCookie); - UserDetails user = userService.getByEmail(request.email()); - return ResponseEntity.ok(new LoginResponseDTO(user.getUsername())); + User user = userService.getByEmail(request.email()); + return ResponseEntity.ok(new LoginResponseDTO(user.getNickname())); } @PostMapping("/logout") @@ -83,7 +82,7 @@ public ResponseEntity logout(HttpServletResponse response) { @PostMapping("/signup") public ResponseEntity signUp(@RequestBody RegisterRequestDTO request) { userService.registerUser(request); - return ResponseEntity.ok(new RegisterResponseDTO(request.username())); + return ResponseEntity.ok(new RegisterResponseDTO(request.nickname())); } @PostMapping("/refresh") diff --git a/src/main/java/com/codzilla/backend/auth/JWTUtils/JWTUtils.java b/src/main/java/com/codzilla/backend/auth/JWTUtils/JWTUtils.java index ce75f40..f790117 100644 --- a/src/main/java/com/codzilla/backend/auth/JWTUtils/JWTUtils.java +++ b/src/main/java/com/codzilla/backend/auth/JWTUtils/JWTUtils.java @@ -23,55 +23,56 @@ public JWTUtils(Settings settings) { public String generateAccessToken(Authentication authentication) { List roles = authentication.getAuthorities().stream() - .map(GrantedAuthority::getAuthority) - .toList(); + .map(GrantedAuthority::getAuthority) + .filter(role -> !role.equals("FACTOR_PASSWORD")) + .toList(); return Jwts.builder() - .subject(authentication.getName()) - .claim("roles", roles) - .issuedAt(new Date()) - .expiration(new Date(System.currentTimeMillis() + settings.getAccessTokenTtl().toMillis())) - .signWith(secret) - .compact(); + .subject(authentication.getName()) + .claim("roles", roles) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + settings.getAccessTokenTtl().toMillis())) + .signWith(secret) + .compact(); } public String generateRefreshToken(Authentication authentication) { return Jwts.builder() - .subject(authentication.getName()) - .setId(UUID.randomUUID().toString()) - .issuedAt(new Date()) - .expiration(new Date(System.currentTimeMillis() + settings.getRefreshTokenTtl().toMillis())) - .signWith(secret) - .compact(); + .subject(authentication.getName()) + .setId(UUID.randomUUID().toString()) + .issuedAt(new Date()) + .expiration(new Date(System.currentTimeMillis() + settings.getRefreshTokenTtl().toMillis())) + .signWith(secret) + .compact(); } public List getRolesFromToken(String token) { Claims claims = Jwts.parser() - .verifyWith(secret) - .build() - .parseSignedClaims(token) - .getPayload(); + .verifyWith(secret) + .build() + .parseSignedClaims(token) + .getPayload(); return claims.get("roles", List.class); } public String getEmailFromToken(String token) { return Jwts.parser() - .verifyWith(secret) - .build() - .parseSignedClaims(token) - .getPayload() - .getSubject(); + .verifyWith(secret) + .build() + .parseSignedClaims(token) + .getPayload() + .getSubject(); } public boolean validateToken(String token) { try { Jwts.parser() - .verifyWith(secret) - .build() - .parseSignedClaims(token); + .verifyWith(secret) + .build() + .parseSignedClaims(token); return true; - } catch (Exception e){ + } catch (Exception e) { return false; } diff --git a/src/main/java/com/codzilla/backend/auth/Repository/UserRepository.java b/src/main/java/com/codzilla/backend/auth/Repository/UserRepository.java index 62c4f65..84f5dce 100644 --- a/src/main/java/com/codzilla/backend/auth/Repository/UserRepository.java +++ b/src/main/java/com/codzilla/backend/auth/Repository/UserRepository.java @@ -7,6 +7,6 @@ public interface UserRepository extends JpaRepository { boolean existsByEmail(String email); - boolean existsByUsername(String username); + boolean existsByNickname(String nickname); Optional findByEmail(String email); } diff --git a/src/main/java/com/codzilla/backend/auth/User.java b/src/main/java/com/codzilla/backend/auth/User.java index a5abfe4..4e56aad 100644 --- a/src/main/java/com/codzilla/backend/auth/User.java +++ b/src/main/java/com/codzilla/backend/auth/User.java @@ -24,7 +24,7 @@ @Table(name = "users") public class User implements UserDetails, CredentialsContainer { - private String username; + private String nickname; private String password; private String email; @@ -53,7 +53,6 @@ public Collection getAuthorities() { } // returns email - @Override public String getUsername() { return email; } diff --git a/src/main/java/com/codzilla/backend/auth/UserService.java b/src/main/java/com/codzilla/backend/auth/UserService.java index 8b766a6..7265901 100644 --- a/src/main/java/com/codzilla/backend/auth/UserService.java +++ b/src/main/java/com/codzilla/backend/auth/UserService.java @@ -6,13 +6,14 @@ import com.codzilla.backend.auth.Repository.UserRepository; import com.codzilla.backend.auth.dto.RegisterRequestDTO; import com.codzilla.backend.auth.dto.UserResponseDTO; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import java.util.List; - +@Slf4j @Service public class UserService { private final UserRepository userRepository; @@ -28,13 +29,13 @@ public void registerUser(RegisterRequestDTO dto) throws UserAlreadyExistsExcepti throw new UserAlreadyExistsException(); } - if (userRepository.existsByUsername(dto.username())) { + if (userRepository.existsByNickname(dto.nickname())) { throw new UsernameIsTakenException(); } - + assert (!dto.email().equals(dto.nickname())); var user = User.builder() .email(dto.email()) - .username(dto.username()) + .nickname(dto.nickname()) .password(passwordEncoder.encode(dto.rawPassword())).build(); userRepository.save(user); @@ -42,7 +43,9 @@ public void registerUser(RegisterRequestDTO dto) throws UserAlreadyExistsExcepti public User getByEmail(String email) { var user = userRepository.findByEmail(email); + if (user.isPresent()) { + log.info("username " + user.get().getNickname()); return user.get(); } else { throw new UserNotFoundException(); @@ -52,7 +55,7 @@ public User getByEmail(String email) { public List getAllUsers() { return userRepository.findAll().stream() .map(user -> new UserResponseDTO( - user.getUsername(), + user.getNickname(), user.getEmail(), user.getId(), user.getAuthorities().stream() @@ -62,10 +65,10 @@ public List getAllUsers() { public void createAdmin() { - if (!userRepository.existsByUsername("admin")) { + if (!userRepository.existsByNickname("a")) { User admin = User.builder() - .username("admin") - .email("admin") + .nickname("a") + .email("a@gmail.com") .password(passwordEncoder.encode("0")) .authorities(List.of(new SimpleGrantedAuthority("ADMIN"))) .build(); diff --git a/src/main/java/com/codzilla/backend/auth/config/SecurityConfig.java b/src/main/java/com/codzilla/backend/auth/config/SecurityConfig.java index 6c40d17..f004316 100644 --- a/src/main/java/com/codzilla/backend/auth/config/SecurityConfig.java +++ b/src/main/java/com/codzilla/backend/auth/config/SecurityConfig.java @@ -21,7 +21,7 @@ @EnableMethodSecurity public class SecurityConfig { - private static final String[] WHITELIST = {"/auth/**"}; + private static final String[] WHITELIST = {"/auth/**", "/error"}; private final HttpStatusEntryPoint unauthorizedHandler; diff --git a/src/main/java/com/codzilla/backend/auth/dto/LoginResponseDTO.java b/src/main/java/com/codzilla/backend/auth/dto/LoginResponseDTO.java index 424b839..42a90c3 100644 --- a/src/main/java/com/codzilla/backend/auth/dto/LoginResponseDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/LoginResponseDTO.java @@ -1,6 +1,6 @@ package com.codzilla.backend.auth.dto; public record LoginResponseDTO( - String username + String nickname ) { } diff --git a/src/main/java/com/codzilla/backend/auth/dto/RegisterRequestDTO.java b/src/main/java/com/codzilla/backend/auth/dto/RegisterRequestDTO.java index de30c33..c21768a 100644 --- a/src/main/java/com/codzilla/backend/auth/dto/RegisterRequestDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/RegisterRequestDTO.java @@ -1,7 +1,7 @@ package com.codzilla.backend.auth.dto; public record RegisterRequestDTO( - String username, + String nickname, String email, String rawPassword ) { diff --git a/src/main/java/com/codzilla/backend/auth/dto/RegisterResponseDTO.java b/src/main/java/com/codzilla/backend/auth/dto/RegisterResponseDTO.java index aa9a73f..9597a96 100644 --- a/src/main/java/com/codzilla/backend/auth/dto/RegisterResponseDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/RegisterResponseDTO.java @@ -1,6 +1,6 @@ package com.codzilla.backend.auth.dto; public record RegisterResponseDTO( - String username + String nickname ) { } diff --git a/src/main/java/com/codzilla/backend/auth/dto/UserResponseDTO.java b/src/main/java/com/codzilla/backend/auth/dto/UserResponseDTO.java index bccce3c..50faeee 100644 --- a/src/main/java/com/codzilla/backend/auth/dto/UserResponseDTO.java +++ b/src/main/java/com/codzilla/backend/auth/dto/UserResponseDTO.java @@ -3,7 +3,7 @@ import java.util.List; public record UserResponseDTO( - String username, + String nickname, String email, Long id, List authorities diff --git a/src/main/java/com/codzilla/backend/controller/Coffee.java b/src/main/java/com/codzilla/backend/controller/Coffee.java deleted file mode 100644 index 01c16ba..0000000 --- a/src/main/java/com/codzilla/backend/controller/Coffee.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.codzilla.backend.controller; - - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; - -import java.util.UUID; - -@Entity -public class Coffee { - - - @Id - private String id ; - private String name; - public void setId(String id) { - this.id = id; - } - - - @JsonCreator - public Coffee(@JsonProperty("id") String id, @JsonProperty("name") String name) { - this.id = id; - this.name = name; - } - - public Coffee() { - this.id = UUID.randomUUID().toString(); - this.name = "DEFAULT"; - - } - - public Coffee(String name) { - this(UUID.randomUUID().toString() , name) ; - } - - public String getId() { - return id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } -} diff --git a/src/main/java/com/codzilla/backend/controller/DataLoader.java b/src/main/java/com/codzilla/backend/controller/DataLoader.java deleted file mode 100644 index dad4e90..0000000 --- a/src/main/java/com/codzilla/backend/controller/DataLoader.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.codzilla.backend.controller; - -import com.codzilla.backend.repository.CoffeeRepository; -import jakarta.annotation.PostConstruct; -import org.springframework.stereotype.Component; - -import java.util.List; - -@Component -public class DataLoader { - public final CoffeeRepository coffeeRepository; - - public DataLoader(CoffeeRepository coffeeRepository) { - this.coffeeRepository = coffeeRepository; - } - - @PostConstruct - private void loadData() { - coffeeRepository.saveAll(List.of( - new Coffee("Café Cereza"), - new Coffee("Café Ganador"), - new Coffee("Café Lareño"), - new Coffee("Café Três Pontas") - )); - } -} diff --git a/src/main/java/com/codzilla/backend/controller/RestApiDemoController.java b/src/main/java/com/codzilla/backend/controller/RestApiDemoController.java deleted file mode 100644 index e7c43a8..0000000 --- a/src/main/java/com/codzilla/backend/controller/RestApiDemoController.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.codzilla.backend.controller; - -import com.codzilla.backend.repository.CoffeeRepository; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; - -import java.util.List; -import java.util.Optional; - -@RestController -@RequestMapping("/coffee") -public class RestApiDemoController { - - private final CoffeeRepository coffeeRepository; -// private final List coffees = new ArrayList<>(); - - public RestApiDemoController(CoffeeRepository coffeeRepository) { - this.coffeeRepository = coffeeRepository; - - this.coffeeRepository.saveAll(List.of( - new Coffee("Café Cereza"), - new Coffee("Café Ganador"), - new Coffee("Café Lareño"), - new Coffee("Café Três Pontas") - )); - } - - - - @RequestMapping(value = "", method = RequestMethod.GET) - Iterable getCoffees() { - return coffeeRepository.findAll(); - } - - @GetMapping("/{id}") - Optional getCoffee(@PathVariable String id) { - return coffeeRepository.findById(id); - } - - @PostMapping - Coffee postCoffee(@RequestBody Coffee coffee) { - return coffeeRepository.save(coffee); - } - -// @PutMapping("/{id}") -// Coffee putCoffee(@PathVariable String id, @RequestBody Coffee coffee) { -// int coffeeIndex = -1; -// for (Coffee c: coffees) { -// if (c.getId().equals(id)) { -// coffeeIndex = coffees.indexOf(c); -// coffees.set(coffeeIndex, coffee); -// } -// } -// return (coffeeIndex == -1) ? postCoffee(coffee) : coffee; -// } - -// @PutMapping("/{id}") -// ResponseEntity putCoffee(@PathVariable String id, -// @RequestBody Coffee coffee) { -// int coffeeIndex = -1; -// for (Coffee c: coffees) { -// if (c.getId().equals(id)) { -// coffeeIndex = coffees.indexOf(c); -// coffees.set(coffeeIndex, coffee); -// } -// } -// return (coffeeIndex == -1) ? -// new ResponseEntity<>(postCoffee(coffee), HttpStatus.CREATED) : -// new ResponseEntity<>(coffee, HttpStatus.OK); -// } - - @PutMapping("/{id}") - ResponseEntity putCoffee(@PathVariable String id , @RequestBody Coffee coffee){ - return (!coffeeRepository.existsById(id)) ? - new ResponseEntity<>(coffeeRepository.save(coffee) , HttpStatus.CREATED) : - new ResponseEntity<>(coffeeRepository.save(coffee) , HttpStatus.OK); - - } - - @DeleteMapping("/{id}") - void deleteCoffee(@PathVariable String id) { - coffeeRepository.deleteById(id); - } -} diff --git a/src/main/java/com/codzilla/backend/repository/CoffeeRepository.java b/src/main/java/com/codzilla/backend/repository/CoffeeRepository.java deleted file mode 100644 index 5039e88..0000000 --- a/src/main/java/com/codzilla/backend/repository/CoffeeRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.codzilla.backend.repository; - -import com.codzilla.backend.controller.Coffee; -import org.springframework.data.repository.CrudRepository; - -public interface CoffeeRepository extends CrudRepository { -} diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index d915375..2b2a7db 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -1,6 +1,6 @@ spring.application.name=AuthService -app.security.jwt.access-token-ttl=10m -app.security.jwt.refresh-token-ttl=7d +app.security.jwt.access-token-ttl=10s +app.security.jwt.refresh-token-ttl=60s spring.datasource.url=${DB_URL} spring.datasource.username=${DB_USERNAME} @@ -8,3 +8,6 @@ spring.datasource.password=${DB_PASSWORD} spring.jpa.hibernate.ddl-auto=update spring.application.name=Backend spring.jpa.show-sql=true + + +logging.level.org.springframework.security=DEBUG \ No newline at end of file diff --git a/src/test/java/com/codzilla/backend/AuthServiceApplicationTests.java b/src/test/java/com/codzilla/backend/AuthServiceApplicationTests.java deleted file mode 100644 index 09b906d..0000000 --- a/src/test/java/com/codzilla/backend/AuthServiceApplicationTests.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.codzilla.backend; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class AuthServiceApplicationTests { - - @Test - void contextLoads() { - assert (true); - } - -} diff --git a/src/test/java/com/codzilla/backend/BaseIntegrationTest.java b/src/test/java/com/codzilla/backend/auth/BaseIntegrationTest.java similarity index 95% rename from src/test/java/com/codzilla/backend/BaseIntegrationTest.java rename to src/test/java/com/codzilla/backend/auth/BaseIntegrationTest.java index 560f423..b778d13 100644 --- a/src/test/java/com/codzilla/backend/BaseIntegrationTest.java +++ b/src/test/java/com/codzilla/backend/auth/BaseIntegrationTest.java @@ -1,4 +1,4 @@ -package com.codzilla.backend; +package com.codzilla.backend.auth; import com.codzilla.backend.auth.Repository.UserRepository; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/test/java/com/codzilla/backend/auth/JwtIntegrationTest.java b/src/test/java/com/codzilla/backend/auth/JwtIntegrationTest.java new file mode 100644 index 0000000..d4a4442 --- /dev/null +++ b/src/test/java/com/codzilla/backend/auth/JwtIntegrationTest.java @@ -0,0 +1,149 @@ +package com.codzilla.backend.auth; + + +import com.codzilla.backend.auth.JWTUtils.JWTUtils; +import com.codzilla.backend.auth.config.Settings; +import com.codzilla.backend.auth.dto.LoginRequestDTO; +import com.codzilla.backend.auth.dto.RegisterRequestDTO; +import jakarta.transaction.Transactional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MvcResult; + +import java.time.Duration; +import java.util.List; +import java.util.Timer; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; + +@SpringBootTest +@Transactional +@AutoConfigureMockMvc +public class JwtIntegrationTest extends BaseIntegrationTest { + + @Autowired + JWTUtils jwtUtils; + + @Autowired + Settings settings; + + @BeforeEach + void setUp() throws Exception { + RegisterRequestDTO registerRequestDTO = new RegisterRequestDTO("nick", "email", "password"); + mockMvc.perform(post("/auth/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(registerRequestDTO))) + .andExpect(status().isOk()); + } + + @Test + void testGetAccessWithJwt() throws Exception { + + RegisterRequestDTO registerRequestDTO = new RegisterRequestDTO("nick", "email", "password"); + LoginRequestDTO loginRequestDTO = new LoginRequestDTO( + registerRequestDTO.email(), + registerRequestDTO.rawPassword() + ); + + MvcResult result = mockMvc.perform(post("/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginRequestDTO))) + .andExpect(status().isOk()) + .andExpect(cookie().exists("jwt")) + .andExpect(cookie().exists("refresh_jwt")) + .andReturn(); + + var JwtCookie = result.getResponse().getCookie("jwt"); + String token = JwtCookie.getValue(); + assertThat(jwtUtils.getEmailFromToken(token)).isEqualTo("email"); + assertThat(jwtUtils.getRolesFromToken(token)).isEqualTo(List.of("USER")); + + mockMvc.perform(get("/endpoint") + .cookie(JwtCookie) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(registerRequestDTO))) + .andExpect(status().isOk()); + } + + @Test + void testExpirationToken() throws Exception { + settings.setAccessTokenTtl(Duration.ZERO); + RegisterRequestDTO registerRequestDTO = new RegisterRequestDTO("nick", "email", "password"); + LoginRequestDTO loginRequestDTO = new LoginRequestDTO( + registerRequestDTO.email(), + registerRequestDTO.rawPassword() + ); + + MvcResult result = mockMvc.perform(post("/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginRequestDTO))) + .andExpect(status().isOk()) + .andExpect(cookie().exists("jwt")) + .andExpect(cookie().exists("refresh_jwt")) + .andReturn(); + + var JwtCookie = result.getResponse().getCookie("jwt"); + + mockMvc.perform(get("/endpoint") + .cookie(JwtCookie) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(registerRequestDTO))) + .andExpect(status().is(401)); + } + + @Test + void testTokenShouldExpiredAndRefreshed() throws Exception { + settings.setAccessTokenTtl(Duration.ofMillis(1000)); + RegisterRequestDTO registerRequestDTO = new RegisterRequestDTO("nick", "email", "password"); + LoginRequestDTO loginRequestDTO = new LoginRequestDTO( + registerRequestDTO.email(), + registerRequestDTO.rawPassword() + ); + + MvcResult result = mockMvc.perform(post("/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginRequestDTO))) + .andExpect(status().isOk()) + .andExpect(cookie().exists("jwt")) + .andExpect(cookie().exists("refresh_jwt")) + .andReturn(); + + var JwtAccessCookie = result.getResponse().getCookie("jwt"); + var JwtRefreshCookie = result.getResponse().getCookie("refresh_jwt"); + + + mockMvc.perform(get("/endpoint") + .cookie(JwtAccessCookie) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(registerRequestDTO))) + .andExpect(status().isOk()); + Thread.sleep(1000); + mockMvc.perform(get("/endpoint") + .cookie(JwtAccessCookie) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(registerRequestDTO))) + .andExpect(status().is(401)); + + MvcResult refresh = mockMvc.perform(post("/auth/refresh") + .cookie(JwtRefreshCookie)) + .andExpect(status().isOk()) + .andExpect(cookie().exists("jwt")) + .andReturn(); + + var newJwtAccessCookie = refresh.getResponse().getCookie("jwt"); + mockMvc.perform(get("/endpoint") + .cookie(newJwtAccessCookie) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(registerRequestDTO))) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/codzilla/backend/auth/LoginIntegrationTest.java b/src/test/java/com/codzilla/backend/auth/LoginIntegrationTest.java new file mode 100644 index 0000000..3619919 --- /dev/null +++ b/src/test/java/com/codzilla/backend/auth/LoginIntegrationTest.java @@ -0,0 +1,57 @@ +package com.codzilla.backend.auth; + +import com.codzilla.backend.auth.JWTUtils.JWTUtils; +import com.codzilla.backend.auth.dto.LoginRequestDTO; +import com.codzilla.backend.auth.dto.LoginResponseDTO; +import com.codzilla.backend.auth.dto.RegisterRequestDTO; +import jakarta.transaction.Transactional; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MvcResult; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@SpringBootTest +@Transactional +@AutoConfigureMockMvc +public class LoginIntegrationTest extends BaseIntegrationTest { + + @Autowired + JWTUtils jwtUtils; + + @Test + void testSimpleLogin() throws Exception { + RegisterRequestDTO registerRequestDTO = new RegisterRequestDTO("nick", "email", "password"); + mockMvc.perform(post("/auth/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(registerRequestDTO))) + .andExpect(status().isOk()); + + LoginRequestDTO loginRequestDTO = new LoginRequestDTO( + registerRequestDTO.email(), + registerRequestDTO.rawPassword() + ); + + LoginResponseDTO expectedResponse = new LoginResponseDTO(registerRequestDTO.nickname()); + + MvcResult result = mockMvc.perform(post("/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginRequestDTO))) + .andExpect(status().isOk()) + .andExpect(content().json( + objectMapper.writeValueAsString(expectedResponse) + )) + .andExpect(cookie().exists("jwt")) + .andExpect(cookie().exists("refresh_jwt")) + .andReturn(); + + } +} diff --git a/src/test/java/com/codzilla/backend/RegisterIntegrationTest.java b/src/test/java/com/codzilla/backend/auth/RegisterIntegrationTest.java similarity index 95% rename from src/test/java/com/codzilla/backend/RegisterIntegrationTest.java rename to src/test/java/com/codzilla/backend/auth/RegisterIntegrationTest.java index 8781d7d..e66df76 100644 --- a/src/test/java/com/codzilla/backend/RegisterIntegrationTest.java +++ b/src/test/java/com/codzilla/backend/auth/RegisterIntegrationTest.java @@ -1,7 +1,6 @@ -package com.codzilla.backend; +package com.codzilla.backend.auth; import com.codzilla.backend.auth.Exceptions.UserAlreadyExistsException; -import com.codzilla.backend.auth.User; import com.codzilla.backend.auth.dto.ErrorResponseDTO; import com.codzilla.backend.auth.dto.RegisterRequestDTO; import com.codzilla.backend.auth.dto.RegisterResponseDTO; @@ -40,7 +39,7 @@ public void testSignUpSimple() throws Exception { .andExpect(content().json(objectMapper.writeValueAsString(expectedResponse))); assert (userRepository.existsByEmail(request.email())); - assert (userRepository.existsByUsername(request.username())); + assert (userRepository.existsByNickname(request.nickname())); User addedUser = userRepository.findByEmail(request.email()).get(); assert (addedUser.getAuthorities().stream().allMatch(s -> { return "USER".equals(s.getAuthority()); diff --git a/src/test/java/com/codzilla/backend/auth/RoleAccessIntegrationTest.java b/src/test/java/com/codzilla/backend/auth/RoleAccessIntegrationTest.java new file mode 100644 index 0000000..a3b5e97 --- /dev/null +++ b/src/test/java/com/codzilla/backend/auth/RoleAccessIntegrationTest.java @@ -0,0 +1,100 @@ +package com.codzilla.backend.auth; + + +import com.codzilla.backend.auth.dto.LoginRequestDTO; +import com.codzilla.backend.auth.dto.RegisterRequestDTO; +import jakarta.transaction.Transactional; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MvcResult; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@Transactional +@AutoConfigureMockMvc +public class RoleAccessIntegrationTest extends BaseIntegrationTest { + + @BeforeEach + void setUp() throws Exception { + RegisterRequestDTO user = new RegisterRequestDTO("nick", "email", "password"); + mockMvc.perform(post("/auth/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(user))) + .andExpect(status().isOk()); + + LoginRequestDTO loginRequestDTO = new LoginRequestDTO( + user.email(), + user.rawPassword() + ); + + MvcResult result = mockMvc.perform(post("/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginRequestDTO))) + .andExpect(status().isOk()) + .andExpect(cookie().exists("jwt")) + .andExpect(cookie().exists("refresh_jwt")) + .andReturn(); + + var accessCookie = result.getResponse().getCookie("jwt"); + + + mockMvc.perform(post("/auth/create-admin") + .contentType(MediaType.APPLICATION_JSON) + .cookie(accessCookie)) + .andExpect(status().isOk()); + } + + @Test + void testUserCantUseAdminEndpoint () throws Exception { + RegisterRequestDTO user = new RegisterRequestDTO("nick", "email", "password"); + LoginRequestDTO loginRequestDTO = new LoginRequestDTO( + user.email(), + user.rawPassword() + ); + + MvcResult result = mockMvc.perform(post("/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginRequestDTO))) + .andExpect(status().isOk()) + .andExpect(cookie().exists("jwt")) + .andExpect(cookie().exists("refresh_jwt")) + .andReturn(); + + var accessCookie = result.getResponse().getCookie("jwt"); + + mockMvc.perform(get("/admin/users") + .cookie(accessCookie)) + .andExpect(status().is(403)); + + } + + @Test + void testAdminCanUseAdminMethod() throws Exception { + RegisterRequestDTO admin = new RegisterRequestDTO("admin", "a@gmail.com", "0"); + LoginRequestDTO loginRequestDTO = new LoginRequestDTO( + admin.email(), + admin.rawPassword() + ); + + MvcResult result = mockMvc.perform(post("/auth/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(loginRequestDTO))) + .andExpect(status().isOk()) + .andExpect(cookie().exists("jwt")) + .andExpect(cookie().exists("refresh_jwt")) + .andReturn(); + + var accessCookie = result.getResponse().getCookie("jwt"); + + mockMvc.perform(get("/admin/users") + .cookie(accessCookie)) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/com/codzilla/backend/controller/CoffeeControllerTest.java b/src/test/java/com/codzilla/backend/controller/CoffeeControllerTest.java deleted file mode 100644 index 8460d86..0000000 --- a/src/test/java/com/codzilla/backend/controller/CoffeeControllerTest.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.codzilla.backend.controller; - -import com.codzilla.backend.repository.CoffeeRepository; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.resttestclient.autoconfigure.AutoConfigureTestRestTemplate; -import org.springframework.boot.test.context.SpringBootTest; -//import org.springframework.boot.test.web.client.TestRestTemplate; -import org.springframework.boot.resttestclient.TestRestTemplate; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -@AutoConfigureTestRestTemplate -class CoffeeControllerTest { - - @Autowired - private TestRestTemplate restTemplate; - - @Autowired - private CoffeeRepository coffeeRepository; - - @BeforeEach - void setUp() { - coffeeRepository.deleteAll(); - } - - @Test - void getCoffees_shouldReturnList() { - coffeeRepository.save(new Coffee("Espresso")); - coffeeRepository.save(new Coffee("Latte")); - - ResponseEntity response = restTemplate.getForEntity("/coffee", Coffee[].class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(response.getBody()).hasSize(2); - } - - @Test - void getCoffee_shouldReturnCoffee_whenExists() { - Coffee saved = coffeeRepository.save(new Coffee("Cappuccino")); - - ResponseEntity response = restTemplate.getForEntity("/coffee/" + saved.getId(), Coffee.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - Assertions.assertNotNull(response.getBody()); - assertThat(response.getBody().getName()).isEqualTo("Cappuccino"); - } - - @Test - void postCoffee_shouldCreateAndReturnCoffee() { - Coffee coffee = new Coffee("Mocha"); - - ResponseEntity response = restTemplate.postForEntity("/coffee", coffee, Coffee.class); - - assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); - Assertions.assertNotNull(response.getBody()); - assertThat(response.getBody().getName()).isEqualTo("Mocha"); - } - - @Test - void deleteCoffee_shouldRemoveCoffee() { - Coffee saved = coffeeRepository.save(new Coffee("ToDelete")); - - restTemplate.delete("/coffee/" + saved.getId()); - - assertThat(coffeeRepository.findById(saved.getId())).isEmpty(); - } -} \ No newline at end of file From 56ed1ff9d2596cead957faab2b59c5eaa0afb43a Mon Sep 17 00:00:00 2001 From: toximu Date: Wed, 11 Mar 2026 22:33:54 +0300 Subject: [PATCH 10/11] change properties --- src/main/resources/application.properties | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2b2a7db..fa8a802 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -5,6 +5,11 @@ app.security.jwt.refresh-token-ttl=60s spring.datasource.url=${DB_URL} spring.datasource.username=${DB_USERNAME} spring.datasource.password=${DB_PASSWORD} + +#spring.datasource.url=jdbc:postgresql://localhost:5433/testingdb +#spring.datasource.username=myuser +#spring.datasource.password=secret + spring.jpa.hibernate.ddl-auto=update spring.application.name=Backend spring.jpa.show-sql=true From db5159a82244736639cf8d6a29017ed93272a66f Mon Sep 17 00:00:00 2001 From: toximu Date: Wed, 11 Mar 2026 22:38:47 +0300 Subject: [PATCH 11/11] change ci java version --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 17c085a..c8fab6f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,10 +14,10 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Set up JDK 21 + - name: Set up JDK 23 uses: actions/setup-java@v4 with: - java-version: '21' + java-version: '23' distribution: 'temurin' - name: Grant execute permission for gradlew