diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000..9c9a32a
Binary files /dev/null and b/.DS_Store differ
diff --git a/.gradle/8.8/checksums/checksums.lock b/.gradle/8.8/checksums/checksums.lock
new file mode 100644
index 0000000..0a0d160
Binary files /dev/null and b/.gradle/8.8/checksums/checksums.lock differ
diff --git a/.gradle/8.8/dependencies-accessors/gc.properties b/.gradle/8.8/dependencies-accessors/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.gradle/8.8/fileChanges/last-build.bin b/.gradle/8.8/fileChanges/last-build.bin
new file mode 100644
index 0000000..f76dd23
Binary files /dev/null and b/.gradle/8.8/fileChanges/last-build.bin differ
diff --git a/.gradle/8.8/fileHashes/fileHashes.lock b/.gradle/8.8/fileHashes/fileHashes.lock
new file mode 100644
index 0000000..b8074bc
Binary files /dev/null and b/.gradle/8.8/fileHashes/fileHashes.lock differ
diff --git a/.gradle/8.8/gc.properties b/.gradle/8.8/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/.gradle/buildOutputCleanup/buildOutputCleanup.lock
new file mode 100644
index 0000000..a8d2a19
Binary files /dev/null and b/.gradle/buildOutputCleanup/buildOutputCleanup.lock differ
diff --git a/.gradle/buildOutputCleanup/cache.properties b/.gradle/buildOutputCleanup/cache.properties
new file mode 100644
index 0000000..1b1c8a0
--- /dev/null
+++ b/.gradle/buildOutputCleanup/cache.properties
@@ -0,0 +1,2 @@
+#Mon Sep 02 17:21:05 KST 2024
+gradle.version=8.8
diff --git a/.gradle/vcs-1/gc.properties b/.gradle/vcs-1/gc.properties
new file mode 100644
index 0000000..e69de29
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 74f1bcb..1fb2494 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -3,6 +3,7 @@
+
\ No newline at end of file
diff --git a/.idea/modules/backend.main.iml b/.idea/modules/backend.main.iml
new file mode 100644
index 0000000..0676e50
--- /dev/null
+++ b/.idea/modules/backend.main.iml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/backend/.DS_Store b/backend/.DS_Store
new file mode 100644
index 0000000..6ef277f
Binary files /dev/null and b/backend/.DS_Store differ
diff --git a/backend/.gitignore b/backend/.gitignore
index c2065bc..ec18673 100644
--- a/backend/.gitignore
+++ b/backend/.gitignore
@@ -19,6 +19,7 @@ bin/
### IntelliJ IDEA ###
.idea
+.idea/
*.iws
*.iml
*.ipr
diff --git a/backend/build.gradle b/backend/build.gradle
index cb425ca..95235d4 100644
--- a/backend/build.gradle
+++ b/backend/build.gradle
@@ -24,6 +24,7 @@ ext {
dependencies {
// Spring Boot starters
+ implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
diff --git a/backend/src/.DS_Store b/backend/src/.DS_Store
new file mode 100644
index 0000000..bc65ca7
Binary files /dev/null and b/backend/src/.DS_Store differ
diff --git a/backend/src/main/.DS_Store b/backend/src/main/.DS_Store
new file mode 100644
index 0000000..c387e22
Binary files /dev/null and b/backend/src/main/.DS_Store differ
diff --git a/backend/src/main/java/.DS_Store b/backend/src/main/java/.DS_Store
new file mode 100644
index 0000000..a832bac
Binary files /dev/null and b/backend/src/main/java/.DS_Store differ
diff --git a/backend/src/main/java/com/.DS_Store b/backend/src/main/java/com/.DS_Store
new file mode 100644
index 0000000..282a4c6
Binary files /dev/null and b/backend/src/main/java/com/.DS_Store differ
diff --git a/backend/src/main/java/com/metlab_project/.DS_Store b/backend/src/main/java/com/metlab_project/.DS_Store
index 8c3a2d3..98c1b2b 100644
Binary files a/backend/src/main/java/com/metlab_project/.DS_Store and b/backend/src/main/java/com/metlab_project/.DS_Store differ
diff --git a/backend/src/main/java/com/metlab_project/backend/.DS_Store b/backend/src/main/java/com/metlab_project/backend/.DS_Store
index 2cb0fe6..83a98a4 100644
Binary files a/backend/src/main/java/com/metlab_project/backend/.DS_Store and b/backend/src/main/java/com/metlab_project/backend/.DS_Store differ
diff --git a/backend/src/main/java/com/metlab_project/backend/controller/chatroom/ChatRoomController.java b/backend/src/main/java/com/metlab_project/backend/controller/chatroom/ChatRoomController.java
index 42d55f1..1c38486 100644
--- a/backend/src/main/java/com/metlab_project/backend/controller/chatroom/ChatRoomController.java
+++ b/backend/src/main/java/com/metlab_project/backend/controller/chatroom/ChatRoomController.java
@@ -1,4 +1,5 @@
package com.metlab_project.backend.controller.chatroom;
+
import com.metlab_project.backend.domain.dto.chatroom.ChatroomCreateRequest;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
@@ -8,54 +9,65 @@
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/chatroom")
-public class ChatroomController {
+public class ChatRoomController {
@GetMapping("/list")
- @Operation(summary="WAITING 상태인 채팅룸 목록 불러오기", description="WAITING 상태인 채팅룸의 목록을 불러옵니다.")
+ @Operation(summary = "WAITING 상태인 채팅룸 목록 불러오기", description = "WAITING 상태인 채팅룸의 목록을 불러옵니다.")
public ResponseEntity> getAllChatroomList() {
try {
-
- } catch () {
+ // TODO: 채팅룸 목록을 불러오는 로직을 구현하세요.
+ } catch (Exception e) {
+ // TODO: 예외 처리 로직을 구현하세요.
+ return ResponseEntity.status(500).body("서버 오류가 발생했습니다.");
}
+ return ResponseEntity.ok("채팅룸 목록"); // TODO: 실제 데이터를 반환하도록 수정하세요.
}
@GetMapping("/list/{schoolEmail}")
- @Operation(summary="유저가 참여하고 있는 채팅룸 목록 불러오기", description="유저가 참여하고 있는 채팅룸의 목록을 불러옵니다.")
- public ResponseEntity> getChatroomList(@PathVariable String schoolEmail){
- try{
-
- }catch(){
-
+ @Operation(summary = "유저가 참여하고 있는 채팅룸 목록 불러오기", description = "유저가 참여하고 있는 채팅룸의 목록을 불러옵니다.")
+ public ResponseEntity> getChatroomList(@PathVariable String schoolEmail) {
+ try {
+ // TODO: 유저가 참여하고 있는 채팅룸 목록을 불러오는 로직을 구현하세요.
+ } catch (Exception e) {
+ // TODO: 예외 처리 로직을 구현하세요.
+ return ResponseEntity.status(500).body("서버 오류가 발생했습니다.");
}
+ return ResponseEntity.ok("참여 중인 채팅룸 목록"); // TODO: 실제 데이터를 반환하도록 수정하세요.
}
@GetMapping("/{chatroomid}/participant")
- @Operation(summary="특정 채팅룸의 참여자 목록 불러오기", description="특정 채팅룸의 참여자 목록을 불러옵니다.")
- public ResponseEntity> getChatroomParticipant(@PathVariable("chatroomid") String chatroomId){
- try{
-
- }catch(){
-
+ @Operation(summary = "특정 채팅룸의 참여자 목록 불러오기", description = "특정 채팅룸의 참여자 목록을 불러옵니다.")
+ public ResponseEntity> getChatroomParticipant(@PathVariable("chatroomid") String chatroomId) {
+ try {
+ // TODO: 특정 채팅룸의 참여자 목록을 불러오는 로직을 구현하세요.
+ } catch (Exception e) {
+ // TODO: 예외 처리 로직을 구현하세요.
+ return ResponseEntity.status(500).body("서버 오류가 발생했습니다.");
}
+ return ResponseEntity.ok("채팅룸 참여자 목록"); // TODO: 실제 데이터를 반환하도록 수정하세요.
}
@PostMapping
- @Operation(summary="채팅룸 생성하기", description="채팅룸을 생성합니다.")
- public ResponseEntity> createChatroom(@RequestBody ChatroomCreateRequest request){
- try{
-
- }catch(){
-
+ @Operation(summary = "채팅룸 생성하기", description = "채팅룸을 생성합니다.")
+ public ResponseEntity> createChatroom(@RequestBody ChatroomCreateRequest request) {
+ try {
+ // TODO: 채팅룸을 생성하는 로직을 구현하세요.
+ } catch (Exception e) {
+ // TODO: 예외 처리 로직을 구현하세요.
+ return ResponseEntity.status(500).body("서버 오류가 발생했습니다.");
}
+ return ResponseEntity.ok("채팅룸 생성 완료"); // TODO: 실제 데이터를 반환하도록 수정하세요.
}
@PostMapping("/activate")
- @Operation(summary="채팅룸 활성화 하기", description="채팅룸의 상태를 active로 전환합니다.")
- public ResponseEntity> activeChatroom(){
- try{
-
- }catch(){
-
+ @Operation(summary = "채팅룸 활성화 하기", description = "채팅룸의 상태를 active로 전환합니다.")
+ public ResponseEntity> activeChatroom() {
+ try {
+ // TODO: 채팅룸을 활성화하는 로직을 구현하세요.
+ } catch (Exception e) {
+ // TODO: 예외 처리 로직을 구현하세요.
+ return ResponseEntity.status(500).body("서버 오류가 발생했습니다.");
}
+ return ResponseEntity.ok("채팅룸 활성화 완료"); // TODO: 실제 데이터를 반환하도록 수정하세요.
}
}
diff --git a/backend/src/main/java/com/metlab_project/backend/controller/user/UserController.java b/backend/src/main/java/com/metlab_project/backend/controller/user/UserController.java
index 1f22f3b..27621ce 100644
--- a/backend/src/main/java/com/metlab_project/backend/controller/user/UserController.java
+++ b/backend/src/main/java/com/metlab_project/backend/controller/user/UserController.java
@@ -1,7 +1,44 @@
package com.metlab_project.backend.controller.user;
-import org.springframework.web.bind.annotation.RestController;
+import com.metlab_project.backend.domain.dto.user.UserInfoResponse;
+import com.metlab_project.backend.service.user.UserService;
+import jakarta.persistence.EntityNotFoundException;
+import lombok.RequiredArgsConstructor;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+@RequiredArgsConstructor
@RestController
+@RequestMapping("/user")
public class UserController {
-}
+
+ private final UserService userService;
+
+ // 유저 정보 가져옴
+ @GetMapping("/{schoolEmail}")
+ public ResponseEntity> getUserInfo(@PathVariable String schoolEmail) {
+ try {
+ UserInfoResponse userInfo = userService.getUserInfoBySchoolEmail(schoolEmail);
+ return new ResponseEntity<>(userInfo, HttpStatus.OK);
+ } catch (EntityNotFoundException ex) {
+ return new ResponseEntity<>("User not found", HttpStatus.NOT_FOUND);
+ }
+ }
+
+ // 유저 정보 수정
+ @PutMapping("/{schoolEmail}")
+ public ResponseEntity> updateUserInfo(@PathVariable String schoolEmail, @RequestBody UserInfoResponse updatedUserInfo) {
+ try {
+ UserInfoResponse updatedUser = userService.updateUserInfo(schoolEmail, updatedUserInfo);
+ return new ResponseEntity<>(updatedUser, HttpStatus.OK);
+ } catch (EntityNotFoundException ex) {
+ return new ResponseEntity<>("User not found", HttpStatus.NOT_FOUND);
+ } catch (IllegalArgumentException ex) {
+ return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
+ }
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/user/CustomUserDetails.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/CustomUserDetails.java
new file mode 100644
index 0000000..b259b5c
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/CustomUserDetails.java
@@ -0,0 +1,55 @@
+package com.metlab_project.backend.domain.dto.user;
+
+import com.metlab_project.backend.domain.entity.User;
+import lombok.RequiredArgsConstructor;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+@RequiredArgsConstructor
+public class CustomUserDetails implements UserDetails {
+ private final User user;
+
+ public Collection extends GrantedAuthority> getAuthorities(){
+ Collection collection = new ArrayList<>();
+ collection.add((GrantedAuthority) () -> user.getRole().toString());
+
+ return collection;
+ }
+
+ public User getUser(){
+ return this.user;
+ }
+
+ @Override
+ public String getUsername(){
+ return user.getSchoolEmail();
+ }
+
+ @Override
+ public String getPassword(){
+ return user.getPassword();
+ }
+
+ @Override
+ public boolean isAccountNonExpired(){
+ return true;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ return true;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ return true;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return true;
+ }
+}
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoRequest.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoRequest.java
new file mode 100644
index 0000000..cc2000a
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoRequest.java
@@ -0,0 +1,22 @@
+package com.metlab_project.backend.domain.dto.user;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserInfoRequest {
+ private String schoolEmail;
+ private String password;
+ private String nickname;
+ private String birthday;
+ private String gender;
+
+ private String studentId;
+ private String college;
+ private String department;
+}
\ No newline at end of file
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse.java
index d10ef8f..20c5fbb 100644
--- a/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse.java
+++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse.java
@@ -1,20 +1,33 @@
package com.metlab_project.backend.domain.dto.user;
-import lombok.AllArgsConstructor;
+import com.metlab_project.backend.domain.entity.User;
+
import lombok.Builder;
-import lombok.Data;
-import lombok.NoArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
+
-@Data
+@Getter
+@Setter
@Builder
-@NoArgsConstructor
-@AllArgsConstructor
public class UserInfoResponse {
private String schoolEmail;
private String nickname;
private String gender;
-
private String studentId;
private String college;
private String department;
+ private UserRole role;
+
+ public static UserInfoResponse from(User user){
+ return UserInfoResponse.builder()
+ .schoolEmail(user.getSchoolEmail())
+ .nickname(user.getNickname())
+ .gender(user.getGender())
+ .studentId(user.getStudentId())
+ .college(user.getCollege())
+ .department(user.getDepartment())
+ .role(user.getRole())
+ .build();
+ }
}
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_BACKUP_42285.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_BACKUP_42285.java
new file mode 100644
index 0000000..20c5fbb
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_BACKUP_42285.java
@@ -0,0 +1,33 @@
+package com.metlab_project.backend.domain.dto.user;
+
+import com.metlab_project.backend.domain.entity.User;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+
+@Getter
+@Setter
+@Builder
+public class UserInfoResponse {
+ private String schoolEmail;
+ private String nickname;
+ private String gender;
+ private String studentId;
+ private String college;
+ private String department;
+ private UserRole role;
+
+ public static UserInfoResponse from(User user){
+ return UserInfoResponse.builder()
+ .schoolEmail(user.getSchoolEmail())
+ .nickname(user.getNickname())
+ .gender(user.getGender())
+ .studentId(user.getStudentId())
+ .college(user.getCollege())
+ .department(user.getDepartment())
+ .role(user.getRole())
+ .build();
+ }
+}
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_BASE_42285.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_BASE_42285.java
new file mode 100644
index 0000000..d10ef8f
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_BASE_42285.java
@@ -0,0 +1,20 @@
+package com.metlab_project.backend.domain.dto.user;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserInfoResponse {
+ private String schoolEmail;
+ private String nickname;
+ private String gender;
+
+ private String studentId;
+ private String college;
+ private String department;
+}
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_LOCAL_42285.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_LOCAL_42285.java
new file mode 100644
index 0000000..ea41b9a
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_LOCAL_42285.java
@@ -0,0 +1,34 @@
+package com.metlab_project.backend.domain.dto.user;
+
+import com.metlab_project.backend.domain.entity.User;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+
+@Getter
+@Setter
+@Builder
+
+public class UserInfoResponse {
+ private String schoolEmail;
+ private String nickname;
+ private String gender;
+ private String studentId;
+ private String college;
+ private String department;
+
+ public static UserInfoResponse from(User user){
+ return UserInfoResponse.builder()
+ .schoolEmail(user.getSchoolEmail())
+ .nickname(user.getNickname())
+ .gender(user.getGender())
+ .studentId(user.getStudentId())
+ .college(user.getCollege())
+ .department(user.getDepartment())
+ .build();
+
+ }
+
+}
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_REMOTE_42285.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_REMOTE_42285.java
new file mode 100644
index 0000000..e695811
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserInfoResponse_REMOTE_42285.java
@@ -0,0 +1,21 @@
+package com.metlab_project.backend.domain.dto.user;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class UserInfoResponse {
+ private String schoolEmail;
+ private String nickname;
+ private String gender;
+
+ private String studentId;
+ private String college;
+ private String department;
+ private UserRole role;
+}
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserRole.java b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserRole.java
new file mode 100644
index 0000000..9738723
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/domain/dto/user/UserRole.java
@@ -0,0 +1,6 @@
+package com.metlab_project.backend.domain.dto.user;
+
+public enum UserRole {
+ ROLE_USER,
+ ROLE_ADMIN
+}
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/entity/RefreshEntity.java b/backend/src/main/java/com/metlab_project/backend/domain/entity/RefreshEntity.java
new file mode 100644
index 0000000..ae8c717
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/domain/entity/RefreshEntity.java
@@ -0,0 +1,31 @@
+package com.metlab_project.backend.domain.entity;
+
+import jakarta.persistence.*;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+
+@Entity
+@Table(name = "refresh_tokens") // 테이블 이름을 지정할 수 있습니다.
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class RefreshEntity {
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(nullable = false, unique = true)
+ private String schoolEmail; // 유저의 이메일(고유)
+
+ @Column(nullable = false)
+ private String token; // Refresh 토큰
+
+ @Column(nullable = false)
+ private Long expiration; // 만료 시간 (초 단위로 저장)
+}
\ No newline at end of file
diff --git a/backend/src/main/java/com/metlab_project/backend/domain/entity/User.java b/backend/src/main/java/com/metlab_project/backend/domain/entity/User.java
index 803c30e..b627999 100644
--- a/backend/src/main/java/com/metlab_project/backend/domain/entity/User.java
+++ b/backend/src/main/java/com/metlab_project/backend/domain/entity/User.java
@@ -1,5 +1,6 @@
package com.metlab_project.backend.domain.entity;
+import com.metlab_project.backend.domain.dto.user.UserRole;
import jakarta.persistence.*;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
@@ -62,6 +63,8 @@ public class User {
private Boolean isblocked;
+ private UserRole role;
+
@ManyToOne
@JoinColumn(name = "chatroom_id", insertable = false, updatable = false)
private ChatRoom chatRoom;
diff --git a/backend/src/main/java/com/metlab_project/backend/repository/user/RefreshTokenRepository.java b/backend/src/main/java/com/metlab_project/backend/repository/user/RefreshTokenRepository.java
new file mode 100644
index 0000000..2936aa2
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/repository/user/RefreshTokenRepository.java
@@ -0,0 +1,14 @@
+package com.metlab_project.backend.repository.user;
+
+import com.metlab_project.backend.domain.entity.RefreshEntity;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+import java.util.Optional;
+
+@Repository
+public interface RefreshTokenRepository extends JpaRepository {
+ Optional findBySchoolEmail(String schoolEmail); // schoolEmail로 조회
+ Boolean existsByToken(String token);
+ Optional findByToken(String token);
+}
diff --git a/backend/src/main/java/com/metlab_project/backend/security/SecurityConfig.java b/backend/src/main/java/com/metlab_project/backend/security/SecurityConfig.java
index a9aedfa..e902a04 100644
--- a/backend/src/main/java/com/metlab_project/backend/security/SecurityConfig.java
+++ b/backend/src/main/java/com/metlab_project/backend/security/SecurityConfig.java
@@ -1,6 +1,6 @@
package com.metlab_project.backend.security;
-import com.metlab_project.backend.security.jwt.JwtTokenFilter;
+import com.metlab_project.backend.security.jwt.JwtAuthenticationFilter;
import com.metlab_project.backend.security.jwt.JwtTokenProvider;
import com.metlab_project.backend.security.jwt.JwtTokenValidator;
import com.metlab_project.backend.service.jwt.BlacklistTokenService;
@@ -59,7 +59,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
.requestMatchers(whiteListUrl.toArray(new String[0])).permitAll()
//.anyRequest().authenticated()
)
- .addFilterBefore(new JwtTokenFilter(userService, jwtTokenProvider,jwtTokenValidator,blacklistTokenService), UsernamePasswordAuthenticationFilter.class);
+ .addFilterBefore(new JwtAuthenticationFilter(userService, jwtTokenProvider,jwtTokenValidator,blacklistTokenService), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
diff --git a/backend/src/main/java/com/metlab_project/backend/security/jwt/CustomLoginFilter.java b/backend/src/main/java/com/metlab_project/backend/security/jwt/CustomLoginFilter.java
new file mode 100644
index 0000000..b3d60b2
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/security/jwt/CustomLoginFilter.java
@@ -0,0 +1,130 @@
+package com.metlab_project.backend.security.jwt;
+
+import com.metlab_project.backend.repository.user.RefreshTokenRepository;
+import com.metlab_project.backend.service.user.UserService;
+
+import io.jsonwebtoken.io.IOException;
+
+import com.metlab_project.backend.domain.entity.RefreshEntity;
+import com.metlab_project.backend.domain.dto.user.UserInfoResponse;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+@Slf4j
+public class CustomLoginFilter extends UsernamePasswordAuthenticationFilter {
+
+ private final RefreshTokenRepository refreshTokenRepository;
+ private final AuthenticationManager authenticationManager;
+ private final JwtTokenProvider jwtTokenProvider; // JwtTokenProvider 사용
+ private final UserService userService; // UserService 사용
+
+ public CustomLoginFilter(AuthenticationManager authenticationManager,
+ RefreshTokenRepository refreshTokenRepository,
+ JwtTokenProvider jwtTokenProvider,
+ UserService userService) {
+ this.refreshTokenRepository = refreshTokenRepository;
+ this.authenticationManager = authenticationManager;
+ this.jwtTokenProvider = jwtTokenProvider;
+ this.userService = userService;
+ setFilterProcessesUrl("/api/users/login");
+ }
+
+ @Override
+ public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
+
+ // 클라이언트 요청에서 username(schoolEmail), password 추출
+ final String schoolEmail = obtainUsername(request); // schoolEmail로 변경
+ final String password = obtainPassword(request);
+
+ log.info("[attemptAuthentication] schoolEmail = {}", schoolEmail);
+ log.info("[attemptAuthentication] password = {}", password);
+
+ // 스프링 시큐리티에서 username과 password를 검증하기 위해서는 token에 담아야 함
+ UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(schoolEmail, password, null);
+
+ // token에 담은 검증을 위한 AuthenticationManager로 전달
+ return authenticationManager.authenticate(authToken);
+ }
+
+ // 로그인 성공시 실행하는 메소드 (여기서 JWT를 발급하면 됨)
+ @Override
+ protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) {
+ log.info("[successfulAuthentication] 로그인 성공");
+
+ Collection extends GrantedAuthority> authorities = authentication.getAuthorities();
+ Iterator extends GrantedAuthority> iterator = authorities.iterator();
+ GrantedAuthority auth = iterator.next();
+
+ final String schoolEmail = authentication.getName();
+ final String role = auth.getAuthority();
+
+ // UserService를 통해 유저 정보 가져오기
+ UserInfoResponse userInfo = userService.getUserInfoBySchoolEmail(schoolEmail);
+
+ // JwtTokenProvider를 사용하여 Access/Refresh 토큰 발급
+ final String accessToken = jwtTokenProvider.generateAccessToken(
+ userInfo.getSchoolEmail(),
+ userInfo.getNickname(),
+ userInfo.getGender(),
+ userInfo.getStudentId(),
+ userInfo.getCollege(),
+ userInfo.getDepartment()
+ );
+ final String refreshToken = jwtTokenProvider.generateRefreshToken(schoolEmail);
+
+ log.info("[successfulAuthentication] schoolEmail = {}", schoolEmail);
+ log.info("[successfulAuthentication] access token = {}", accessToken);
+ log.info("[successfulAuthentication] refresh token = {}", refreshToken);
+
+ // Refresh 토큰 저장
+ addRefreshEntity(schoolEmail, refreshToken, jwtTokenProvider.getExpirationDateFromToken(refreshToken).getTime());
+
+ // Authorization 헤더와 쿠키 설정
+ response.addHeader("Authorization", "Bearer " + accessToken);
+ response.addCookie(createCookie("refresh", refreshToken, jwtTokenProvider.getExpirationDateFromToken(refreshToken).getTime()));
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+
+ private void addRefreshEntity(String schoolEmail, String refresh, Long refreshExpireTime) {
+ // 기존에 존재하는 Refresh 토큰 삭제
+ refreshTokenRepository.findBySchoolEmail(schoolEmail).ifPresent(refreshTokenRepository::delete);
+
+ RefreshEntity refreshEntity = RefreshEntity.builder()
+ .schoolEmail(schoolEmail)
+ .token(refresh)
+ .expiration(refreshExpireTime)
+ .build();
+
+ refreshTokenRepository.save(refreshEntity);
+ }
+
+ private Cookie createCookie(String key, String value, Long refreshExpireTime) {
+ Cookie cookie = new Cookie(key, value);
+ cookie.setHttpOnly(true);
+ cookie.setMaxAge(Math.toIntExact(refreshExpireTime / 1000));
+ cookie.setSecure(true); // HTTPS에서만 전송
+ cookie.setPath("/"); // 경로 지정
+ return cookie;
+ }
+
+ //로그인 실패시 실행하는 메소드
+ @Override
+ protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
+ log.info("[successfulAuthentication] 로그인 실패");
+ response.setStatus(401);
+ }
+
+}
diff --git a/backend/src/main/java/com/metlab_project/backend/security/jwt/CustomLogoutFilter.java b/backend/src/main/java/com/metlab_project/backend/security/jwt/CustomLogoutFilter.java
new file mode 100644
index 0000000..ac68968
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/security/jwt/CustomLogoutFilter.java
@@ -0,0 +1,142 @@
+package com.metlab_project.backend.security.jwt;
+
+import com.metlab_project.backend.repository.user.RefreshTokenRepository;
+import com.metlab_project.backend.domain.entity.RefreshEntity;
+import com.metlab_project.backend.service.user.UserService;
+import io.jsonwebtoken.ExpiredJwtException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.filter.GenericFilterBean;
+
+import java.io.IOException;
+
+@RequiredArgsConstructor
+@Slf4j
+public class CustomLogoutFilter extends GenericFilterBean {
+
+ private final JwtTokenProvider jwtTokenProvider; // JwtTokenProvider
+ private final RefreshTokenRepository refreshTokenRepository;
+
+
+ @Override
+ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+ doFilter((HttpServletRequest) request, (HttpServletResponse) response, chain);
+ }
+
+ /**
+ * 로그아웃 필터
+ * @param request
+ * @param response
+ * @param filterChain
+ * @throws IOException
+ * @throws ServletException
+ */
+ private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
+
+ // Logout Request 검증
+ if (verifiedLogoutRequest(request, response, filterChain)) return;
+
+ // Cookie에서 Refresh Token 가져오기
+ String refreshToken = null;
+ Cookie[] cookies = request.getCookies();
+ if (cookies == null) {
+ doStatusBadRequest("[doFilter] cookies are null", response);
+ return;
+ }
+ for (Cookie cookie : cookies) {
+ if ("refresh".equals(cookie.getName())) {
+ refreshToken = cookie.getValue();
+ }
+ }
+
+ // Refresh Token 검증
+ if (!validateRefreshToken(response, refreshToken)) return;
+
+ // 로그아웃 진행
+ log.info("[doFilter] Logging out");
+
+ // Refresh 토큰 DB에서 제거
+ refreshTokenRepository.findByToken(refreshToken).ifPresent(refreshTokenRepository::delete);
+
+ // Refresh 토큰 Cookie 삭제
+ Cookie cookie = new Cookie("refresh", null);
+ cookie.setMaxAge(0);
+ cookie.setPath("/");
+
+ response.addCookie(cookie);
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+
+ /**
+ * 로그아웃 요청 검증
+ * @param request
+ * @param response
+ * @param filterChain
+ * @return boolean
+ * @throws IOException
+ * @throws ServletException
+ */
+ private static boolean verifiedLogoutRequest(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
+ // 로그아웃 요청이 /api/users/logout으로 와야 하고, 메서드는 POST여야 함
+ final String requestUri = request.getRequestURI();
+ if (!"/api/users/logout".equals(requestUri)) {
+ filterChain.doFilter(request, response);
+ return true;
+ }
+ final String requestMethod = request.getMethod();
+ if (!"POST".equals(requestMethod)) {
+ filterChain.doFilter(request, response);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Refresh Token 검증
+ * @param response
+ * @param refreshToken
+ * @return
+ */
+ private boolean validateRefreshToken(HttpServletResponse response, String refreshToken) {
+ // refresh token이 없는 경우
+ if (refreshToken == null) {
+ doStatusBadRequest("[doFilter] refreshToken is null", response);
+ return false;
+ }
+
+ // 토큰 만료 검증
+ try {
+ jwtTokenProvider.isExpired(refreshToken);
+ } catch (ExpiredJwtException e) {
+ doStatusBadRequest("[doFilter] refreshToken is expired", response);
+ return false;
+ }
+
+ // 토큰이 refresh 토큰인지 확인
+ String category = jwtTokenProvider.getCategory(refreshToken);
+ if (!"refresh".equals(category)) {
+ doStatusBadRequest("[doFilter] token is not a refresh token", response);
+ return false;
+ }
+
+ // DB에 저장되어 있는지 확인
+ if (!refreshTokenRepository.existsByToken(refreshToken)) {
+ doStatusBadRequest("[doFilter] refreshToken does not exist in repository", response);
+ return false;
+ }
+
+ return true;
+ }
+
+ private static void doStatusBadRequest(String msg, HttpServletResponse response) {
+ log.info(msg);
+ response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+ }
+}
diff --git a/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenFilter.java b/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtAuthenticationFilter.java
similarity index 67%
rename from backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenFilter.java
rename to backend/src/main/java/com/metlab_project/backend/security/jwt/JwtAuthenticationFilter.java
index 36397d1..47e94ac 100644
--- a/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenFilter.java
+++ b/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtAuthenticationFilter.java
@@ -1,19 +1,19 @@
package com.metlab_project.backend.security.jwt;
+import com.metlab_project.backend.domain.dto.user.CustomUserDetails;
import com.metlab_project.backend.domain.dto.user.UserInfoResponse;
+import com.metlab_project.backend.domain.dto.user.UserRole;
+import com.metlab_project.backend.domain.entity.User;
import com.metlab_project.backend.exception.TokenException;
import com.metlab_project.backend.service.jwt.BlacklistTokenService;
import com.metlab_project.backend.service.user.UserService;
-
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
-
import lombok.RequiredArgsConstructor;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -28,14 +28,14 @@
import java.util.List;
@RequiredArgsConstructor
-public class JwtTokenFilter extends OncePerRequestFilter implements Filter {
+public class JwtAuthenticationFilter extends OncePerRequestFilter implements Filter {
private final UserService userService;
private final JwtTokenProvider jwtTokenProvider;
private final JwtTokenValidator jwtTokenValidator;
private final BlacklistTokenService blacklistTokenService;
- private static final Logger logger = LoggerFactory.getLogger(JwtTokenFilter.class);
+ private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);
private static final AntPathMatcher pathMatcher = new AntPathMatcher();
private static final List whiteListUrl = Arrays.asList(
@@ -45,36 +45,46 @@ public class JwtTokenFilter extends OncePerRequestFilter implements Filter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
- throws ServletException, IOException{
+ throws ServletException, IOException {
logger.info("Enter JwtTokenFilter with {}", request.getRequestURI());
String accessToken = getTokenFromHttpRequest(request);
- if(isPermittedUrl(request.getRequestURI())){
+ if (isPermittedUrl(request.getRequestURI())) {
filterChain.doFilter(request, response);
return;
}
- try{
- boolean isValidate = (accessToken != null) && (!jwtTokenValidator.validateAccessToken(accessToken))
- && blacklistTokenService.isBlacklisted(accessToken);
+ try {
+ jwtTokenValidator.validateAccessToken(accessToken);
- if(isValidate){
- UserInfoResponse user = jwtTokenProvider.getUserInfoFromJwt(accessToken);
- Authentication auth = new UsernamePasswordAuthenticationToken(user.getSchoolEmail(), null, Collections.emptyList());
- SecurityContextHolder.getContext().setAuthentication(auth);
- }
- }catch(TokenException e){
+ String username = jwtTokenProvider.getUserInfo(accessToken).getSchoolEmail();
+ UserRole userRole = jwtTokenProvider.getUserInfo(accessToken).getRole();
+
+ User user = User.builder()
+ .schoolEmail(username)
+ .role(userRole)
+ .build();
+
+ CustomUserDetails customUserDetails = new CustomUserDetails(user);
+
+ Authentication authentication = new UsernamePasswordAuthenticationToken(customUserDetails,null, customUserDetails.getAuthorities());
+
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+
+ filterChain.doFilter(request,response);
+
+ } catch (TokenException e) {
logger.warn("JwtException Occurred");
- handleTokenException(request,response, e, accessToken);
- }catch (Exception e){
+ handleTokenException(request, response, e, accessToken);
+ } catch (Exception e) {
SecurityContextHolder.clearContext();
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response.getWriter().write("UnExpected Error with : " + e.getMessage());
}
}
- private String getTokenFromHttpRequest(HttpServletRequest request){
+ private String getTokenFromHttpRequest(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
@@ -87,19 +97,19 @@ private String getTokenFromHttpRequest(HttpServletRequest request){
return null;
}
- private boolean isPermittedUrl(String requestUri){
+ private boolean isPermittedUrl(String requestUri) {
return whiteListUrl.stream()
.anyMatch(uri -> pathMatcher.match(uri, requestUri));
}
- private void handleTokenException(HttpServletRequest request, HttpServletResponse response, TokenException e, String accessToken) throws IOException{
- switch (e.getErrorCode()){
- case TOKEN_EXPIRED:
- try{
+ private void handleTokenException(HttpServletRequest request, HttpServletResponse response, TokenException e, String accessToken) throws IOException {
+ switch (e.getErrorCode()) {
+ case TOKEN_EXPIRED:
+ try {
String schoolEmail = jwtTokenProvider.getSchoolEmailFromExpiredToken(accessToken);
String refreshToken = userService.getRefreshToken(schoolEmail);
- if((refreshToken != null) && jwtTokenValidator.validateRefreshToken(refreshToken)){
+ if ((refreshToken != null) && jwtTokenValidator.validateRefreshToken(refreshToken)) {
UserInfoResponse user = userService.getUserInfoBySchoolEmail(schoolEmail);
String newAccessToken = jwtTokenProvider.generateAccessToken(user.getSchoolEmail(), user.getNickname(), user.getGender(),
user.getStudentId(), user.getCollege(), user.getDepartment());
@@ -107,14 +117,14 @@ private void handleTokenException(HttpServletRequest request, HttpServletRespons
Cookie cookie = new Cookie("JWT", newAccessToken);
cookie.setHttpOnly(true);
cookie.setPath("/");
- cookie.setMaxAge(60*60);
+ cookie.setMaxAge(60 * 60);
response.addCookie(cookie);
Authentication auth = new UsernamePasswordAuthenticationToken(user.getSchoolEmail(), null, Collections.emptyList());
SecurityContextHolder.getContext().setAuthentication(auth);
}
- }catch(TokenException error){
+ } catch (TokenException error) {
SecurityContextHolder.clearContext();
Cookie jwtCookie = new Cookie("JWT", null);
@@ -126,16 +136,17 @@ private void handleTokenException(HttpServletRequest request, HttpServletRespons
response.getWriter().write("Token error: " + error.getMessage());
}
break;
- case TOKEN_INVALID:
- sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
- break;
- case TOKEN_MISSING:
- sendErrorResponse(response, HttpServletResponse.SC_BAD_REQUEST, "Token is missing");
- break;
- default:
- sendErrorResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "An unexpected error occurred");
- }
-
+ case TOKEN_INVALID:
+ sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
+ break;
+ case TOKEN_MISSING:
+ sendErrorResponse(response, HttpServletResponse.SC_BAD_REQUEST, "Token is missing");
+ break;
+ case TOKEN_BLACKLISTED:
+ sendErrorResponse(response, HttpServletResponse.SC_BAD_REQUEST, "Token is blackListed");
+ default:
+ sendErrorResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "An unexpected error occurred");
+ }
}
private void sendErrorResponse(HttpServletResponse response, int status, String message) throws IOException {
diff --git a/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenProvider.java b/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenProvider.java
index 1b81301..8a55c45 100644
--- a/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenProvider.java
+++ b/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenProvider.java
@@ -2,6 +2,7 @@
import com.metlab_project.backend.domain.dto.user.UserInfoResponse;
+import com.metlab_project.backend.domain.dto.user.UserRole;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
@@ -46,6 +47,7 @@ public String generateAccessToken(String schoolEmail, String nickname, String ge
claims.put("gender", gender);
claims.put("college", college);
claims.put("department", department);
+ claims.put("role", UserRole.ROLE_USER);
String token = Jwts.builder()
.setHeader(header)
@@ -67,21 +69,24 @@ public String generateRefreshToken(String schoolEmail){
.compact();
}
- public UserInfoResponse getUserInfoFromJwt(String accessToken){
+ public UserInfoResponse getUserInfo(String accessToken){
Claims claims = Jwts.parserBuilder()
.setSigningKey(accessKey)
.build()
.parseClaimsJws(accessToken)
.getBody();
- return new UserInfoResponse(
- claims.getSubject(),
- claims.get("nickname", String.class),
- claims.get("gender", String.class),
- claims.get("studentId", String.class),
- claims.get("college", String.class),
- claims.get("department", String.class)
- );
+
+ return UserInfoResponse.builder()
+ .schoolEmail(claims.getSubject())
+ .nickname(claims.get("nickname", String.class))
+ .gender(claims.get("gender", String.class))
+ .studentId(claims.get("studentId", String.class))
+ .college(claims.get("college", String.class))
+ .department(claims.get("department", String.class))
+ .role(claims.get("role", UserRole.class))
+ .build();
+
}
public String getSchoolEmailFromExpiredToken(String token){
@@ -105,6 +110,20 @@ public Date getExpirationDateFromToken(String token){
.getBody().getExpiration();
}
+ public boolean isExpired(String token) {
+ Date expiration = getExpirationDateFromToken(token);
+ return expiration.before(new Date());
+ }
+
+ public String getCategory(String token) {
+ Claims claims = Jwts.parserBuilder()
+ .setSigningKey(accessKey) // or refreshKey depending on the token type
+ .build()
+ .parseClaimsJws(token)
+ .getBody();
+ return claims.get("category", String.class);
+ }
+
private Map createJwtHeader(){
Map header = new HashMap<>();
header.put("typ", "JWT");
diff --git a/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenValidator.java b/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenValidator.java
index 66a38a2..0b58e3d 100644
--- a/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenValidator.java
+++ b/backend/src/main/java/com/metlab_project/backend/security/jwt/JwtTokenValidator.java
@@ -1,12 +1,15 @@
package com.metlab_project.backend.security.jwt;
import com.metlab_project.backend.exception.TokenException;
+import com.metlab_project.backend.service.jwt.BlacklistTokenService;
import io.jsonwebtoken.*;
import io.jsonwebtoken.security.SignatureException;
+import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
+@RequiredArgsConstructor
public class JwtTokenValidator {
@Value("${jwt.secret.access}")
@@ -15,7 +18,12 @@ public class JwtTokenValidator {
@Value("${jwt.secret.refresh}")
private String refreshTokenSecret;
+ private final BlacklistTokenService blacklistTokenService;
+
public boolean validateAccessToken(String token) {
+ if (blacklistTokenService.isBlacklisted(token))
+ throw new TokenException(TokenException.TokenErrorCode.TOKEN_BLACKLISTED);
+
try {
Claims claims = Jwts.parserBuilder()
.setSigningKey(accessTokenSecret.getBytes())
diff --git a/backend/src/main/java/com/metlab_project/backend/service/user/CustomUserDetailsService.java b/backend/src/main/java/com/metlab_project/backend/service/user/CustomUserDetailsService.java
new file mode 100644
index 0000000..1b9a6f9
--- /dev/null
+++ b/backend/src/main/java/com/metlab_project/backend/service/user/CustomUserDetailsService.java
@@ -0,0 +1,24 @@
+package com.metlab_project.backend.service.user;
+
+import com.metlab_project.backend.domain.dto.user.CustomUserDetails;
+import com.metlab_project.backend.domain.entity.User;
+import com.metlab_project.backend.repository.user.UserRepository;
+import lombok.RequiredArgsConstructor;
+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
+@RequiredArgsConstructor
+public class CustomUserDetailsService implements UserDetailsService {
+ private final UserRepository userRepository;
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException{
+ User user = userRepository.findBySchoolEmail(username)
+ .orElseThrow(() -> new UsernameNotFoundException("Find User by Username(SchoolEmail) is failed" + username));
+
+ return new CustomUserDetails(user);
+ }
+}
\ No newline at end of file
diff --git a/backend/src/main/java/com/metlab_project/backend/service/user/UserService.java b/backend/src/main/java/com/metlab_project/backend/service/user/UserService.java
index 30cdc29..e77b6e5 100644
--- a/backend/src/main/java/com/metlab_project/backend/service/user/UserService.java
+++ b/backend/src/main/java/com/metlab_project/backend/service/user/UserService.java
@@ -5,7 +5,6 @@
import com.metlab_project.backend.repository.user.UserRepository;
import lombok.RequiredArgsConstructor;
-
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -16,7 +15,7 @@
public class UserService {
private final UserRepository userRepository;
- public UserInfoResponse getUserInfoBySchoolEmail(String schoolEmail){
+ public UserInfoResponse getUserInfoBySchoolEmail(String schoolEmail) {
User user = userRepository.findBySchoolEmail(schoolEmail)
.orElseThrow(() -> new BadCredentialsException("Invalid Email"));
@@ -30,10 +29,35 @@ public UserInfoResponse getUserInfoBySchoolEmail(String schoolEmail){
.build();
}
- public String getRefreshToken(String schoolEmail){
+ public String getRefreshToken(String schoolEmail) {
User user = userRepository.findBySchoolEmail(schoolEmail)
.orElseThrow(() -> new BadCredentialsException("Invalid Email"));
return user.getRefreshtoken();
}
+
+ public UserInfoResponse updateUserInfo(String schoolEmail, UserInfoResponse userInfoResponse) {
+ User user = userRepository.findBySchoolEmail(schoolEmail)
+ .orElseThrow(() -> new RuntimeException("User not found"));
+
+ // User 엔티티의 정보를 UserInfoResponse의 값으로 업데이트
+ user.setNickname(userInfoResponse.getNickname());
+ user.setGender(userInfoResponse.getGender());
+ user.setStudentId(userInfoResponse.getStudentId());
+ user.setCollege(userInfoResponse.getCollege());
+ user.setDepartment(userInfoResponse.getDepartment());
+
+ // 저장
+ User updatedUser = userRepository.save(user);
+
+ // UserInfoResponse로 변환하여 반환
+ return UserInfoResponse.builder()
+ .schoolEmail(updatedUser.getSchoolEmail())
+ .nickname(updatedUser.getNickname())
+ .gender(updatedUser.getGender())
+ .studentId(updatedUser.getStudentId())
+ .college(updatedUser.getCollege())
+ .department(updatedUser.getDepartment())
+ .build();
+ }
}