From 27ea5ac6cbebd5f93ece9be3549bd7510d6c721e Mon Sep 17 00:00:00 2001 From: LeeShinHaeng Date: Fri, 3 Jan 2025 23:18:41 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refactor:=20public=20endpoint=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/kgu/developers/common/config/SecurityConfig.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/aics-common/src/main/java/kgu/developers/common/config/SecurityConfig.java b/aics-common/src/main/java/kgu/developers/common/config/SecurityConfig.java index b7dd3ad8..a529d539 100644 --- a/aics-common/src/main/java/kgu/developers/common/config/SecurityConfig.java +++ b/aics-common/src/main/java/kgu/developers/common/config/SecurityConfig.java @@ -75,6 +75,9 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { "/api/v1/auth/**", "/api/v1/professors", "/api/v1/abouts", + "/api/v1/posts/**", + "/api/v1/labs", + "/api/v1/comments", }; CorsConfigurationSource corsConfigurationSource() { From 5a4a8bd59168e92eaf5f5a74cfc88985db2ad122 Mon Sep 17 00:00:00 2001 From: LeeShinHaeng Date: Fri, 3 Jan 2025 23:29:14 +0900 Subject: [PATCH 2/8] =?UTF-8?q?refactor:=20PreAuthorize=EB=A5=BC=20?= =?UTF-8?q?=EC=9D=B4=EC=9A=A9=ED=95=9C=20ROLE=20=EC=9A=94=EC=B2=AD=20?= =?UTF-8?q?=EC=A0=9C=ED=95=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/about/presentation/AboutAdminController.java | 2 ++ .../admin/comment/presentation/CommentAdminController.java | 2 ++ .../developers/admin/file/presentation/FileAdminController.java | 2 ++ .../developers/admin/lab/presentation/LabAdminController.java | 2 ++ .../developers/admin/post/presentation/PostAdminController.java | 2 ++ .../admin/professor/presentation/ProfessorAdminController.java | 2 ++ .../developers/admin/user/presentation/UserAdminController.java | 2 ++ 7 files changed, 14 insertions(+) diff --git a/aics-admin/src/main/java/kgu/developers/admin/about/presentation/AboutAdminController.java b/aics-admin/src/main/java/kgu/developers/admin/about/presentation/AboutAdminController.java index 09c2b84d..82ecd3dd 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/about/presentation/AboutAdminController.java +++ b/aics-admin/src/main/java/kgu/developers/admin/about/presentation/AboutAdminController.java @@ -4,6 +4,7 @@ import static org.springframework.http.HttpStatus.NO_CONTENT; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -25,6 +26,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/abouts") +@PreAuthorize("hasRole('ROLE_ADMIN')") @Tag(name = "About", description = "소개글 관리자 API") public class AboutAdminController { private final AboutAdminFacade aboutAdminFacade; diff --git a/aics-admin/src/main/java/kgu/developers/admin/comment/presentation/CommentAdminController.java b/aics-admin/src/main/java/kgu/developers/admin/comment/presentation/CommentAdminController.java index e0c48f12..2b12d2c5 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/comment/presentation/CommentAdminController.java +++ b/aics-admin/src/main/java/kgu/developers/admin/comment/presentation/CommentAdminController.java @@ -1,5 +1,6 @@ package kgu.developers.admin.comment.presentation; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -10,6 +11,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/comments") +@PreAuthorize("hasRole('ROLE_ADMIN')") @Tag(name = "Comment", description = "댓글 관리자 API") public class CommentAdminController { private final CommentAdminFacade commentAdminFacade; diff --git a/aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminController.java b/aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminController.java index 478b3c87..9c948083 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminController.java +++ b/aics-admin/src/main/java/kgu/developers/admin/file/presentation/FileAdminController.java @@ -7,6 +7,7 @@ import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -28,6 +29,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/files") +@PreAuthorize("hasRole('ROLE_ADMIN')") @Tag(name = "File", description = "파일 업로드 관리 API") public class FileAdminController { private final FileAdminFacade fileAdminFacade; diff --git a/aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminController.java b/aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminController.java index 9d4a8987..313c853b 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminController.java +++ b/aics-admin/src/main/java/kgu/developers/admin/lab/presentation/LabAdminController.java @@ -3,6 +3,7 @@ import static org.springframework.http.HttpStatus.CREATED; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -27,6 +28,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/labs") +@PreAuthorize("hasRole('ROLE_ADMIN')") @Tag(name = "Lab", description = "연구실 관리자 API") public class LabAdminController { private final LabAdminFacade labAdminFacade; diff --git a/aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminController.java b/aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminController.java index 453eec7f..8e08b6ab 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminController.java +++ b/aics-admin/src/main/java/kgu/developers/admin/post/presentation/PostAdminController.java @@ -3,6 +3,7 @@ import static org.springframework.http.HttpStatus.CREATED; 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.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -28,6 +29,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/posts") +@PreAuthorize("hasRole('ROLE_ADMIN')") @Tag(name = "Post", description = "게시글 관리자 API") public class PostAdminController { private final PostAdminFacade postAdminFacade; diff --git a/aics-admin/src/main/java/kgu/developers/admin/professor/presentation/ProfessorAdminController.java b/aics-admin/src/main/java/kgu/developers/admin/professor/presentation/ProfessorAdminController.java index 14e3ee24..17708e34 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/professor/presentation/ProfessorAdminController.java +++ b/aics-admin/src/main/java/kgu/developers/admin/professor/presentation/ProfessorAdminController.java @@ -3,6 +3,7 @@ import static org.springframework.http.HttpStatus.CREATED; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -27,6 +28,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/professors") +@PreAuthorize("hasRole('ROLE_ADMIN')") @Tag(name = "Professor", description = "교수 관리자 API") public class ProfessorAdminController { private final ProfessorAdminFacade professorAdminFacade; diff --git a/aics-admin/src/main/java/kgu/developers/admin/user/presentation/UserAdminController.java b/aics-admin/src/main/java/kgu/developers/admin/user/presentation/UserAdminController.java index cff6cd61..edeab360 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/user/presentation/UserAdminController.java +++ b/aics-admin/src/main/java/kgu/developers/admin/user/presentation/UserAdminController.java @@ -2,6 +2,7 @@ import org.springframework.data.domain.PageRequest; 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.RequestParam; @@ -22,6 +23,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/users") +@PreAuthorize("hasRole('ROLE_ADMIN')") @Tag(name = "User", description = "회원 관리자 API") public class UserAdminController { private final UserAdminFacade userAdminFacade; From 8a3371990b17dcd3ad448a25192afb29ca36f417 Mon Sep 17 00:00:00 2001 From: LeeShinHaeng Date: Sat, 4 Jan 2025 09:37:41 +0900 Subject: [PATCH 3/8] =?UTF-8?q?refactor:=20ClubAdminController=20PreAuthor?= =?UTF-8?q?ize=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../developers/admin/club/presentation/ClubAdminController.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aics-admin/src/main/java/kgu/developers/admin/club/presentation/ClubAdminController.java b/aics-admin/src/main/java/kgu/developers/admin/club/presentation/ClubAdminController.java index 3a6c70bf..38d95bf2 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/club/presentation/ClubAdminController.java +++ b/aics-admin/src/main/java/kgu/developers/admin/club/presentation/ClubAdminController.java @@ -3,6 +3,7 @@ import static org.springframework.http.HttpStatus.CREATED; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -27,6 +28,7 @@ @RestController @RequiredArgsConstructor @RequestMapping("/api/v1/clubs") +@PreAuthorize("hasRole('ROLE_ADMIN')") @Tag(name = "Club", description = "동아리 관리자 API") public class ClubAdminController { private final ClubAdminFacade clubAdminFacade; From edc07d98792aca752b1c8c19a3d1b64dca9eff1f Mon Sep 17 00:00:00 2001 From: LeeShinHaeng Date: Sun, 5 Jan 2025 11:52:49 +0900 Subject: [PATCH 4/8] =?UTF-8?q?refactor:=20RestControllerAdvice=EB=A5=BC?= =?UTF-8?q?=20=EC=9D=B4=EC=9A=A9=ED=95=9C=20Exception=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminAuthorizeExceptionHandler.java | 20 ++++++++++++++++ .../admin/exception/AdminExceptionCode.java | 24 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java create mode 100644 aics-admin/src/main/java/kgu/developers/admin/exception/AdminExceptionCode.java diff --git a/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java b/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java new file mode 100644 index 00000000..dd23e78c --- /dev/null +++ b/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java @@ -0,0 +1,20 @@ +package kgu.developers.admin.aspect; + +import static kgu.developers.admin.exception.AdminExceptionCode.NOT_ADMIN; + +import kgu.developers.common.exception.ExceptionResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + + +@RestControllerAdvice +public class AdminAuthorizeExceptionHandler { + @ExceptionHandler(AccessDeniedException.class) + public ResponseEntity handleAccessDeniedException() { + ExceptionResponse response = ExceptionResponse.from(NOT_ADMIN); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body(response); + } +} diff --git a/aics-admin/src/main/java/kgu/developers/admin/exception/AdminExceptionCode.java b/aics-admin/src/main/java/kgu/developers/admin/exception/AdminExceptionCode.java new file mode 100644 index 00000000..1be68bfa --- /dev/null +++ b/aics-admin/src/main/java/kgu/developers/admin/exception/AdminExceptionCode.java @@ -0,0 +1,24 @@ +package kgu.developers.admin.exception; + +import static org.springframework.http.HttpStatus.FORBIDDEN; + +import kgu.developers.common.exception.ExceptionCode; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +@AllArgsConstructor +public enum AdminExceptionCode implements ExceptionCode { + NOT_ADMIN(FORBIDDEN, "관리자 전용 API입니다."), + ; + + private final HttpStatus status; + private final String message; + + + @Override + public String getCode() { + return this.name(); + } +} From 0396539ade7cd1d41d42678e9006c23f180a2944 Mon Sep 17 00:00:00 2001 From: LeeShinHaeng Date: Sun, 5 Jan 2025 19:24:34 +0900 Subject: [PATCH 5/8] =?UTF-8?q?refactor:=20=EC=BD=94=EB=93=9C=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=A4=EC=85=98=20=EC=A4=80=EC=88=98=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20HttpStatus=20static=20import=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/aspect/AdminAuthorizeExceptionHandler.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java b/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java index dd23e78c..2fd677fa 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java +++ b/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java @@ -1,20 +1,19 @@ package kgu.developers.admin.aspect; import static kgu.developers.admin.exception.AdminExceptionCode.NOT_ADMIN; +import static org.springframework.http.HttpStatus.FORBIDDEN; import kgu.developers.common.exception.ExceptionResponse; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.AccessDeniedException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; - @RestControllerAdvice public class AdminAuthorizeExceptionHandler { @ExceptionHandler(AccessDeniedException.class) public ResponseEntity handleAccessDeniedException() { ExceptionResponse response = ExceptionResponse.from(NOT_ADMIN); - return ResponseEntity.status(HttpStatus.FORBIDDEN).body(response); + return ResponseEntity.status(FORBIDDEN).body(response); } } From 9f3b706b7c7fd80f5aea68ae729e49da84d7f1ea Mon Sep 17 00:00:00 2001 From: LeeShinHaeng Date: Mon, 6 Jan 2025 09:47:43 +0900 Subject: [PATCH 6/8] =?UTF-8?q?refactor:=20User=EC=9D=98=20Role=EC=9D=84?= =?UTF-8?q?=20BaseRole=EB=A1=9C=20=EB=B3=80=EA=B2=BD=20=ED=9B=84=20common?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/kgu/developers/common/domain/BaseRole.java | 4 ++-- .../user/application/response/UserDetailResponse.java | 4 ++-- .../main/java/kgu/developers/domain/user/domain/User.java | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) rename aics-domain/src/main/java/kgu/developers/domain/user/domain/Role.java => aics-common/src/main/java/kgu/developers/common/domain/BaseRole.java (77%) diff --git a/aics-domain/src/main/java/kgu/developers/domain/user/domain/Role.java b/aics-common/src/main/java/kgu/developers/common/domain/BaseRole.java similarity index 77% rename from aics-domain/src/main/java/kgu/developers/domain/user/domain/Role.java rename to aics-common/src/main/java/kgu/developers/common/domain/BaseRole.java index 35b12dbb..f82560d0 100644 --- a/aics-domain/src/main/java/kgu/developers/domain/user/domain/Role.java +++ b/aics-common/src/main/java/kgu/developers/common/domain/BaseRole.java @@ -1,11 +1,11 @@ -package kgu.developers.domain.user.domain; +package kgu.developers.common.domain; import lombok.Getter; import lombok.RequiredArgsConstructor; @Getter @RequiredArgsConstructor -public enum Role { +public enum BaseRole { USER("일반사용자"), ADMIN("관리자"), diff --git a/aics-domain/src/main/java/kgu/developers/domain/user/application/response/UserDetailResponse.java b/aics-domain/src/main/java/kgu/developers/domain/user/application/response/UserDetailResponse.java index 991399d8..8dfab71f 100644 --- a/aics-domain/src/main/java/kgu/developers/domain/user/application/response/UserDetailResponse.java +++ b/aics-domain/src/main/java/kgu/developers/domain/user/application/response/UserDetailResponse.java @@ -4,7 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import kgu.developers.domain.user.domain.Major; -import kgu.developers.domain.user.domain.Role; +import kgu.developers.common.domain.BaseRole; import kgu.developers.domain.user.domain.User; import lombok.Builder; @@ -20,7 +20,7 @@ public record UserDetailResponse( String email, @Schema(description = "구분", example = "학부생", requiredMode = REQUIRED) - Role role, + BaseRole role, @Schema(description = "학과", example = "컴퓨터공학과", requiredMode = REQUIRED) Major major, diff --git a/aics-domain/src/main/java/kgu/developers/domain/user/domain/User.java b/aics-domain/src/main/java/kgu/developers/domain/user/domain/User.java index 2e4211cf..d713f682 100644 --- a/aics-domain/src/main/java/kgu/developers/domain/user/domain/User.java +++ b/aics-domain/src/main/java/kgu/developers/domain/user/domain/User.java @@ -11,10 +11,10 @@ import java.util.Collections; import java.util.List; +import kgu.developers.common.domain.BaseRole; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import jakarta.persistence.Column; @@ -59,7 +59,7 @@ public class User extends BaseTimeEntity implements UserDetails { @Column(nullable = false) @Enumerated(STRING) - private Role role; + private BaseRole role; @Column(nullable = false) @Enumerated(STRING) @@ -78,7 +78,7 @@ public static User create(String id, String password, String name, String email, .name(name) .email(email) .phone(phone) - .role(Role.USER) + .role(BaseRole.USER) .major(major) .build(); } @@ -95,7 +95,7 @@ public void updatePhone(String phone) { @Override public Collection getAuthorities() { - return Collections.singletonList(new SimpleGrantedAuthority(Role.USER.name())); + return Collections.singletonList(new SimpleGrantedAuthority(BaseRole.USER.name())); } @Override From b623440c9bbad92b2b2d3ef6f6a008765547cacd Mon Sep 17 00:00:00 2001 From: LeeShinHaeng Date: Mon, 6 Jan 2025 10:04:59 +0900 Subject: [PATCH 7/8] =?UTF-8?q?refactor:=20getAuthentication=20Role?= =?UTF-8?q?=EC=97=90=20=EB=94=B0=EB=A5=B8=20authorities=20=EB=B6=84?= =?UTF-8?q?=EA=B8=B0=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/auth/application/AuthService.java | 22 +-- .../common/auth/jwt/TokenProvider.java | 128 ++++++++++-------- 2 files changed, 81 insertions(+), 69 deletions(-) diff --git a/aics-api/src/main/java/kgu/developers/api/auth/application/AuthService.java b/aics-api/src/main/java/kgu/developers/api/auth/application/AuthService.java index 8c92e0ce..37f068d4 100644 --- a/aics-api/src/main/java/kgu/developers/api/auth/application/AuthService.java +++ b/aics-api/src/main/java/kgu/developers/api/auth/application/AuthService.java @@ -1,11 +1,5 @@ package kgu.developers.api.auth.application; -import java.time.Duration; - -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - import kgu.developers.api.auth.presentation.exception.TokenNotFoundException; import kgu.developers.api.auth.presentation.request.LoginRequest; import kgu.developers.api.auth.presentation.request.RefreshTokenRequest; @@ -17,6 +11,11 @@ import kgu.developers.domain.user.domain.User; import lombok.Builder; import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.Duration; @Service @Builder @@ -35,8 +34,9 @@ public TokenResponse login(LoginRequest request) { User user = userQueryService.getUserById(userId); user.isPasswordMatching(password, passwordEncoder); - String refreshToken = tokenProvider.generateToken(user.getId(), Duration.ofDays(1)); - String accessToken = tokenProvider.generateToken(user.getId(), Duration.ofHours(1)); + String role = user.getRole().name(); + String refreshToken = tokenProvider.generateToken(user.getId(), Duration.ofDays(1), role); + String accessToken = tokenProvider.generateToken(user.getId(), Duration.ofHours(1), role); refreshTokenRepository.save(RefreshToken.of(userId, refreshToken)); return TokenResponse.of(accessToken, refreshToken); @@ -50,8 +50,10 @@ public TokenResponse reissue(RefreshTokenRequest request) { refreshTokenRepository.delete(refreshTokenEntity); String userId = refreshTokenEntity.getUserId(); - String refreshToken = tokenProvider.generateToken(userId, Duration.ofDays(1)); - String accessToken = tokenProvider.generateToken(userId, Duration.ofHours(1)); + User user = userQueryService.getUserById(userId); + String role = user.getRole().name(); + String refreshToken = tokenProvider.generateToken(userId, Duration.ofDays(1), role); + String accessToken = tokenProvider.generateToken(userId, Duration.ofHours(1), role); refreshTokenRepository.save(RefreshToken.of(userId, refreshToken)); return TokenResponse.of(accessToken, refreshToken); } diff --git a/aics-common/src/main/java/kgu/developers/common/auth/jwt/TokenProvider.java b/aics-common/src/main/java/kgu/developers/common/auth/jwt/TokenProvider.java index 50237caa..0709958f 100644 --- a/aics-common/src/main/java/kgu/developers/common/auth/jwt/TokenProvider.java +++ b/aics-common/src/main/java/kgu/developers/common/auth/jwt/TokenProvider.java @@ -4,79 +4,89 @@ import static io.jsonwebtoken.SignatureAlgorithm.HS256; import static javax.xml.crypto.dsig.SignatureProperties.TYPE; -import java.time.Duration; -import java.util.Collections; -import java.util.Date; -import java.util.Set; - +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import lombok.Builder; +import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Service; -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import lombok.Builder; -import lombok.RequiredArgsConstructor; +import java.time.Duration; +import java.util.Collections; +import java.util.Date; +import java.util.Set; @Service @Builder @RequiredArgsConstructor public class TokenProvider { - private final JwtProperties jwtProperties; + private final JwtProperties jwtProperties; + + public String generateToken(String userId, Duration expiredAt, String role) { + Date now = new Date(); + return makeToken(new Date(now.getTime() + expiredAt.toMillis()), userId, role); + } + + private String makeToken(Date expiry, String userId, String role) { + Date now = new Date(); + return Jwts.builder() + .setHeaderParam(TYPE, JWT_TYPE) + .setIssuer(jwtProperties.getIssuer()) + .setIssuedAt(now) + .setExpiration(expiry) + .setSubject(userId) + .claim("userId", userId) + .claim("role", role) + .signWith(HS256, jwtProperties.getSecretKey()) + .compact(); + } - public String generateToken(String userId, Duration expiredAt) { - Date now = new Date(); - return makeToken(new Date(now.getTime() + expiredAt.toMillis()), userId); - } + public boolean validateToken(String token) { + try { + Jwts.parser() + .setSigningKey(jwtProperties.getSecretKey()) + .parseClaimsJws(token); + return true; + } catch (Exception e) { + return false; + } + } - private String makeToken(Date expiry, String userId) { - Date now = new Date(); - return Jwts.builder() - .setHeaderParam(TYPE, JWT_TYPE) - .setIssuer(jwtProperties.getIssuer()) - .setIssuedAt(now) - .setExpiration(expiry) - .setSubject(userId) - .claim("userId", userId) - .signWith(HS256, jwtProperties.getSecretKey()) - .compact(); - } + public Authentication getAuthentication(String token) { + Claims claims = getClaims(token); + String role = claims.get("role", String.class); + Set authorities = getRoles(role); - public boolean validateToken(String token) { - try { - Jwts.parser() - .setSigningKey(jwtProperties.getSecretKey()) - .parseClaimsJws(token); - return true; - } catch (Exception e) { - return false; - } - } + return new UsernamePasswordAuthenticationToken( + new org.springframework.security.core.userdetails.User( + claims.getSubject(), + "", + authorities + ), token, authorities + ); + } - public Authentication getAuthentication(String token) { - Claims claims = getClaims(token); - Set authorities = Collections.singleton( - new SimpleGrantedAuthority("ROLE_USER") - ); - return new UsernamePasswordAuthenticationToken( - new org.springframework.security.core.userdetails.User( - claims.getSubject(), - "", - authorities - ), token, authorities - ); - } + public Set getRoles(String role) { + if (role.equals("ADMIN")) { + return Collections.singleton(new SimpleGrantedAuthority("ROLE_ADMIN")); + } + if (role.equals("SUPER")) { + return Collections.singleton(new SimpleGrantedAuthority("ROLE_SUPER")); + } + return Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")); + } - public String getUserId(String token) { - Claims claims = getClaims(token); - return claims.get("userId", String.class); - } + public String getUserId(String token) { + Claims claims = getClaims(token); + return claims.get("userId", String.class); + } - private Claims getClaims(String token) { - return Jwts.parser() - .setSigningKey(jwtProperties.getSecretKey()) - .parseClaimsJws(token) - .getBody(); - } + private Claims getClaims(String token) { + return Jwts.parser() + .setSigningKey(jwtProperties.getSecretKey()) + .parseClaimsJws(token) + .getBody(); + } } From 93aea4285e3ee2b2b17fa919a46807427f6a1664 Mon Sep 17 00:00:00 2001 From: LeeShinHaeng Date: Mon, 6 Jan 2025 10:16:39 +0900 Subject: [PATCH 8/8] =?UTF-8?q?refactor:=20GlobalExceptionHandler=EB=A1=9C?= =?UTF-8?q?=20ExceptionHandler=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminAuthorizeExceptionHandler.java | 19 ------------- .../common}/exception/AdminExceptionCode.java | 3 +- .../exception/GlobalExceptionHandler.java | 28 ++++++++++++------- 3 files changed, 19 insertions(+), 31 deletions(-) delete mode 100644 aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java rename {aics-admin/src/main/java/kgu/developers/admin => aics-common/src/main/java/kgu/developers/common}/exception/AdminExceptionCode.java (82%) diff --git a/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java b/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java deleted file mode 100644 index 2fd677fa..00000000 --- a/aics-admin/src/main/java/kgu/developers/admin/aspect/AdminAuthorizeExceptionHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package kgu.developers.admin.aspect; - -import static kgu.developers.admin.exception.AdminExceptionCode.NOT_ADMIN; -import static org.springframework.http.HttpStatus.FORBIDDEN; - -import kgu.developers.common.exception.ExceptionResponse; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.RestControllerAdvice; - -@RestControllerAdvice -public class AdminAuthorizeExceptionHandler { - @ExceptionHandler(AccessDeniedException.class) - public ResponseEntity handleAccessDeniedException() { - ExceptionResponse response = ExceptionResponse.from(NOT_ADMIN); - return ResponseEntity.status(FORBIDDEN).body(response); - } -} diff --git a/aics-admin/src/main/java/kgu/developers/admin/exception/AdminExceptionCode.java b/aics-common/src/main/java/kgu/developers/common/exception/AdminExceptionCode.java similarity index 82% rename from aics-admin/src/main/java/kgu/developers/admin/exception/AdminExceptionCode.java rename to aics-common/src/main/java/kgu/developers/common/exception/AdminExceptionCode.java index 1be68bfa..a1841814 100644 --- a/aics-admin/src/main/java/kgu/developers/admin/exception/AdminExceptionCode.java +++ b/aics-common/src/main/java/kgu/developers/common/exception/AdminExceptionCode.java @@ -1,8 +1,7 @@ -package kgu.developers.admin.exception; +package kgu.developers.common.exception; import static org.springframework.http.HttpStatus.FORBIDDEN; -import kgu.developers.common.exception.ExceptionCode; import lombok.AllArgsConstructor; import lombok.Getter; import org.springframework.http.HttpStatus; diff --git a/aics-common/src/main/java/kgu/developers/common/exception/GlobalExceptionHandler.java b/aics-common/src/main/java/kgu/developers/common/exception/GlobalExceptionHandler.java index 4e1e708c..ea76f884 100644 --- a/aics-common/src/main/java/kgu/developers/common/exception/GlobalExceptionHandler.java +++ b/aics-common/src/main/java/kgu/developers/common/exception/GlobalExceptionHandler.java @@ -1,17 +1,19 @@ package kgu.developers.common.exception; +import static kgu.developers.common.exception.AdminExceptionCode.NOT_ADMIN; import static kgu.developers.common.exception.GlobalExceptionCode.INVALID_INPUT; import static kgu.developers.common.exception.GlobalExceptionCode.SERVER_ERROR; +import static org.springframework.http.HttpStatus.FORBIDDEN; -import java.util.List; -import java.util.stream.Collectors; - +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.TypeMismatchException; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.MessageSourceResolvable; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; import org.springframework.validation.method.ParameterValidationResult; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -20,8 +22,8 @@ import org.springframework.web.method.annotation.HandlerMethodValidationException; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; +import java.util.List; +import java.util.stream.Collectors; @Slf4j @RestControllerAdvice @@ -29,6 +31,12 @@ public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { private final ApplicationEventPublisher eventPublisher; + @ExceptionHandler(AccessDeniedException.class) + public ResponseEntity handleAccessDeniedException() { + ExceptionResponse response = ExceptionResponse.from(NOT_ADMIN); + return ResponseEntity.status(FORBIDDEN).body(response); + } + @ExceptionHandler(CustomException.class) protected ResponseEntity handleCustomException(CustomException exception) { if (exception.isServerError()) @@ -45,7 +53,7 @@ protected ResponseEntity handleException(Exception exception) @Override protected ResponseEntity handleHandlerMethodValidationException(HandlerMethodValidationException exception, - HttpHeaders headers, HttpStatusCode status, WebRequest request) { + HttpHeaders headers, HttpStatusCode status, WebRequest request) { String message = exception.getParameterValidationResults().stream() .map(ParameterValidationResult::getResolvableErrors) @@ -59,7 +67,7 @@ protected ResponseEntity handleHandlerMethodValidationException(HandlerM @Override protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException exception, - HttpHeaders headers, HttpStatusCode status, WebRequest request) { + HttpHeaders headers, HttpStatusCode status, WebRequest request) { String message = exception.getFieldErrors().stream() .map(error -> error.getField() + ": " + error.getDefaultMessage()) @@ -71,9 +79,9 @@ protected ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotV @Override protected ResponseEntity handleTypeMismatch(TypeMismatchException exception, - HttpHeaders headers, - HttpStatusCode status, - WebRequest request) { + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { String message = String.format("Failed to convert '%s' with value: '%s'.", exception.getPropertyName(), exception.getValue());