From 38727c221b73102e81369ff8247cf36c544067ec Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:15:32 +0900 Subject: [PATCH 01/17] =?UTF-8?q?#29=20refactor:=20user=5Faccount=20Table?= =?UTF-8?q?=EC=97=90=20sub(=ED=9A=8C=EC=9B=90=20=EB=B2=88=ED=98=B8)=20colu?= =?UTF-8?q?mn=20=EA=B0=92=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/UserAccount.java | 20 +- src/main/resources/data.sql | 213 +++++++++--------- 2 files changed, 123 insertions(+), 110 deletions(-) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/domain/UserAccount.java b/src/main/java/com/example/pnuunivmiryangcampus/domain/UserAccount.java index 51f5813..bb38feb 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/domain/UserAccount.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/domain/UserAccount.java @@ -2,13 +2,16 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; import lombok.Getter; import lombok.ToString; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Getter @ToString(callSuper = true) +@EntityListeners(AuditingEntityListener.class) @Entity -public class UserAccount extends AuditingFields{ +public class UserAccount extends AuditingFields { @Column(nullable = false) private String profileNickname; @@ -16,19 +19,28 @@ public class UserAccount extends AuditingFields{ @Column(nullable = false, length = 100) private String accountEmail; + @Column(nullable = false) + private String sub; + @Column private String memo; + @Column(nullable = false, length = 100, updatable = false) + private String createdBy; + protected UserAccount() { } - private UserAccount(String profileNickname, String accountEmail, String memo) { + private UserAccount(String profileNickname, String accountEmail, String sub, String memo, String createdBy) { this.profileNickname = profileNickname; this.accountEmail = accountEmail; + this.sub = sub; this.memo = memo; + this.createdBy = createdBy; } - public static UserAccount of(String profileNickname, String accountEmail, String memo) { - return new UserAccount(profileNickname, accountEmail, memo); + public static UserAccount of(String profileNickname, String accountEmail, String sub, String memo, + String createdBy) { + return new UserAccount(profileNickname, accountEmail, sub, memo, createdBy); } } diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 2971158..83ce96b 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -1,110 +1,111 @@ -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (1, 1, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (2, 2, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (3, 3, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (4, 4, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (5, 5, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (6, 6, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (7, 7, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (8, 8, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (9, 9, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (10, 10, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (11, 11, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (12, 12, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (13, 13, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (14, 14, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (15, 15, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (16, 16, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (17, 17, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (18, 18, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (19, 19, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (20, 20, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (21, 21, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (22, 22, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (23, 23, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (24, 24, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (25, 25, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (26, 26, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (27, 27, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (28, 28, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (29, 29, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (30, 30, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (31, 31, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (32, 32, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (33, 33, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (34, 34, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (35, 35, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (36, 36, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (37, 37, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (38, 38, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (39, 39, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (40, 40, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (41, 41, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (42, 42, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (43, 43, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (44, 44, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (45, 45, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (46, 46, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (47, 47, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (48, 48, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (49, 49, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (50, 50, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (51, 51, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into library_seat(id, seat_number,availability, created_by, created_at, modified_by, modified_at, is_deleted) values - (52, 52, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (1, 1, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (2, 2, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (3, 3, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (4, 4, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (5, 5, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (6, 6, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (7, 7, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (8, 8, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (9, 9, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (10, 10, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (11, 11, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (12, 12, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (13, 13, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (14, 14, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (15, 15, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (16, 16, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (17, 17, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (18, 18, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (19, 19, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (20, 20, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (21, 21, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (22, 22, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (23, 23, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (24, 24, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (25, 25, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (26, 26, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (27, 27, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (28, 28, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (29, 29, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (30, 30, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (31, 31, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (32, 32, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (33, 33, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (34, 34, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (35, 35, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (36, 36, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (37, 37, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (38, 38, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (39, 39, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (40, 40, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (41, 41, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (42, 42, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (43, 43, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (44, 44, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (45, 45, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (46, 46, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (47, 47, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (48, 48, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (49, 49, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (50, 50, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (51, 51, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into library_seat(id, seat_number, availability, created_by, created_at, modified_by, modified_at, is_deleted) +values (52, 52, '사용가능', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); -insert into user_account(id, profile_nickname, account_email, memo, created_by, created_at, modified_by, modified_at, is_deleted) values - (1, '김세훈', 'shggm2000@naver.com', '관리자', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); +insert into user_account(id, profile_nickname, account_email, sub, memo, created_by, created_at, modified_by, + modified_at, is_deleted) +values (1, '김세훈', 'shggm2000@naver.com', '123456789', '관리자', '김세훈', CURRENT_TIMESTAMP, NULL, NULL, false); From a6e0a2a277ccf3bfa892c8391b18db24b6a1ebb7 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:16:11 +0900 Subject: [PATCH 02/17] =?UTF-8?q?#29=20feat:=20user=5Faccount=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20DTO=20=EB=B0=8F=20Repository=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/UserAccountDto.java | 57 +++++++++++++++++++ .../repository/UserAccountRepository.java | 10 ++++ 2 files changed, 67 insertions(+) create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/dto/UserAccountDto.java create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/repository/UserAccountRepository.java diff --git a/src/main/java/com/example/pnuunivmiryangcampus/dto/UserAccountDto.java b/src/main/java/com/example/pnuunivmiryangcampus/dto/UserAccountDto.java new file mode 100644 index 0000000..a6c6b9f --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/dto/UserAccountDto.java @@ -0,0 +1,57 @@ +package com.example.pnuunivmiryangcampus.dto; + +import com.example.pnuunivmiryangcampus.domain.UserAccount; +import java.io.Serializable; +import java.time.LocalDateTime; + +public record UserAccountDto( + Long id, + LocalDateTime createdAt, + String createdBy, + LocalDateTime modifiedAt, + String modifiedBy, + boolean isDeleted, + String profileNickname, + String accountEmail, + String sub, + String memo + ) implements Serializable { + + public static UserAccountDto of(Long id, LocalDateTime createdAt, String createdBy, LocalDateTime modifiedAt, String modifiedBy, boolean isDeleted, String profileNickname, + String accountEmail, + String sub, + String memo) { + + return new UserAccountDto(id, createdAt, createdBy, modifiedAt, modifiedBy, isDeleted, profileNickname, + accountEmail, sub, memo); + } + + public static UserAccountDto of(String profileNickname, String accountEmail, String sub) { + return new UserAccountDto(null, null, profileNickname, null, null, false, profileNickname, accountEmail, sub, null); + } + + public static UserAccountDto from(UserAccount entity) { + return new UserAccountDto( + entity.getId(), + entity.getCreatedAt(), + entity.getCreatedBy(), + entity.getModifiedAt(), + entity.getModifiedBy(), + entity.isDeleted(), + entity.getProfileNickname(), + entity.getAccountEmail(), + entity.getSub(), + entity.getMemo() + ); + } + + public UserAccount toEntity() { + return UserAccount.of( + profileNickname, + accountEmail, + sub, + memo, + createdBy + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/pnuunivmiryangcampus/repository/UserAccountRepository.java b/src/main/java/com/example/pnuunivmiryangcampus/repository/UserAccountRepository.java new file mode 100644 index 0000000..68ce336 --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/repository/UserAccountRepository.java @@ -0,0 +1,10 @@ +package com.example.pnuunivmiryangcampus.repository; + +import com.example.pnuunivmiryangcampus.domain.UserAccount; +import java.util.Optional; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface UserAccountRepository extends JpaRepository { + + Optional findBySub(String sub); +} \ No newline at end of file From 0f4eb3c43cda0a356cc4eb6fbdd03abf5d346c07 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:19:33 +0900 Subject: [PATCH 03/17] =?UTF-8?q?#29=20chore:=20=EA=B3=B5=EA=B0=9C?= =?UTF-8?q?=ED=82=A4=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EC=BA=90=EC=8B=B1?= =?UTF-8?q?=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=9C=20redis=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - redis 윈도우용 서버를 따로 설치 후 실행해야함 --- build.gradle | 1 + .../PnuUnivMiryangCampusApplication.java | 3 ++- src/main/resources/application.yml | 7 +++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index ee0c03b..d043bfb 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' + implementation 'org.springframework.boot:spring-boot-starter-data-redis' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.h2database:h2' diff --git a/src/main/java/com/example/pnuunivmiryangcampus/PnuUnivMiryangCampusApplication.java b/src/main/java/com/example/pnuunivmiryangcampus/PnuUnivMiryangCampusApplication.java index ae06c30..b5ded29 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/PnuUnivMiryangCampusApplication.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/PnuUnivMiryangCampusApplication.java @@ -2,12 +2,13 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; +import org.springframework.cache.annotation.EnableCaching; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @EnableJpaAuditing @EnableFeignClients +@EnableCaching @SpringBootApplication public class PnuUnivMiryangCampusApplication { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0a28556..0e11ce9 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -29,6 +29,10 @@ spring: default-batch-fetch-size: 100 h2.console.enabled: true sql.init.mode: always + data: + redis: + port: 6379 + host: localhost feign: client: @@ -38,8 +42,7 @@ feign: auth-url: https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=b4610d35ecbcd2e97cadaac137434c74&redirect_uri=http://pnu-univ-miryang-campus-env.ap-northeast-2.elasticbeanstalk.com/auth/kakao/callback token-uri: token rest-api-key: b4610d35ecbcd2e97cadaac137434c74 - redirect-uri: http://pnu-univ-miryang-campus-env.ap-northeast-2.elasticbeanstalk.com/auth/kakao/callback + redirect-uri: http://localhost:5000/auth/kakao/callback grant-type: authorization_code - From 428ea449a7eacd4596a34657809ce3a81d61ef8e Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:20:19 +0900 Subject: [PATCH 04/17] =?UTF-8?q?#29=20feat:=20RedisCacheConfig=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/RedisCacheConfig.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/auth/RedisCacheConfig.java diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/RedisCacheConfig.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/RedisCacheConfig.java new file mode 100644 index 0000000..079c0f3 --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/RedisCacheConfig.java @@ -0,0 +1,34 @@ +package com.example.pnuunivmiryangcampus.auth; + +import java.time.Duration; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +@EnableCaching +@Configuration +public class RedisCacheConfig { + @Bean + public CacheManager oidcCacheManager(RedisConnectionFactory cf) { + RedisCacheConfiguration redisCacheConfiguration = + RedisCacheConfiguration.defaultCacheConfig() + .serializeKeysWith( + RedisSerializationContext.SerializationPair.fromSerializer( + new StringRedisSerializer())) + .serializeValuesWith( + RedisSerializationContext.SerializationPair.fromSerializer( + new GenericJackson2JsonRedisSerializer())) + .entryTtl(Duration.ofDays(7L)); + + return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(cf) + .cacheDefaults(redisCacheConfiguration) + .build(); + } +} \ No newline at end of file From dc92268d711e8237ab3f5a89812144dc46724439 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:24:08 +0900 Subject: [PATCH 05/17] =?UTF-8?q?#29=20feat:=20kakao=20login=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20yml=20=ED=8C=8C=EC=9D=BC=20=EB=B3=80=EA=B2=BD=20?= =?UTF-8?q?=EB=B0=8F=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0e11ce9..b9d9f22 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -38,11 +38,16 @@ feign: client: kakao: name: kakaoLogin - base-url: https://kauth.kakao.com/oauth/ - auth-url: https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=b4610d35ecbcd2e97cadaac137434c74&redirect_uri=http://pnu-univ-miryang-campus-env.ap-northeast-2.elasticbeanstalk.com/auth/kakao/callback - token-uri: token + base-url: https://kauth.kakao.com + auth-url: https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=b4610d35ecbcd2e97cadaac137434c74&redirect_uri=http://localhost:5000/auth/kakao/callback + token-uri: /oauth/token + oicd-open-key-uri: /.well-known/jwks.json rest-api-key: b4610d35ecbcd2e97cadaac137434c74 redirect-uri: http://localhost:5000/auth/kakao/callback grant-type: authorization_code + oicd-base-url: https://kapi.kakao.com + oicd-userinfo-uri: /v1/oidc/userinfo + + From 6f2e97c3faf6e67ed1a43034ed4c06464d5483a6 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:25:19 +0900 Subject: [PATCH 06/17] =?UTF-8?q?#29=20feat:=20=EA=B3=B5=EA=B0=9C=20?= =?UTF-8?q?=ED=82=A4=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EC=BA=90=EC=8B=B1?= =?UTF-8?q?=ED=95=B4=EC=84=9C=20=EA=B0=80=EC=A0=B8=EC=98=A4=EB=8A=94=20get?= =?UTF-8?q?KakaoOIDCOpenKeys=20method=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{KakaoApiCaller.java => KakaoOauthClient.java} | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) rename src/main/java/com/example/pnuunivmiryangcampus/auth/{KakaoApiCaller.java => KakaoOauthClient.java} (55%) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoApiCaller.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoOauthClient.java similarity index 55% rename from src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoApiCaller.java rename to src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoOauthClient.java index e36ca16..9b2079f 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoApiCaller.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoOauthClient.java @@ -1,16 +1,24 @@ package com.example.pnuunivmiryangcampus.auth; import com.example.pnuunivmiryangcampus.dto.KakaoTokenDto; +import org.springframework.cache.annotation.Cacheable; import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; -@FeignClient(name = "${feign.client.kakao.name}", url = "${feign.client.kakao.base-url}") -public interface KakaoApiCaller { +@FeignClient( + name = "KakaoOauthClient", + url = "${feign.client.kakao.base-url}") +public interface KakaoOauthClient { - @PostMapping("/${feign.client.kakao.token-uri}") + @PostMapping("${feign.client.kakao.token-uri}") KakaoTokenDto getKakaoToken(@RequestParam("client_id") String restApiKey, @RequestParam("redirect_uri") String redirectUrl, @RequestParam("code") String code, @RequestParam("grant_type") String grantType); + + @Cacheable(cacheNames = "KakaoOICD", cacheManager = "oidcCacheManager") + @GetMapping("${feign.client.kakao.oicd-open-key-uri}") + OIDCPublicKeysResponse getKakaoOIDCOpenKeys(); } From c8dbb25b45eddbec903254142cde3710eec6918e Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:27:38 +0900 Subject: [PATCH 07/17] =?UTF-8?q?#29=20feat:=20KakaoInfoClient=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 카카오 사용자의 서비스 가입에는 사용자 정보 가져오기 API를 필수적으로 호출해야함 - 해당 API를 호출하기 위한 FeignClient --- .../pnuunivmiryangcampus/auth/KakaoInfoClient.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoInfoClient.java diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoInfoClient.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoInfoClient.java new file mode 100644 index 0000000..81c0014 --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoInfoClient.java @@ -0,0 +1,14 @@ +package com.example.pnuunivmiryangcampus.auth; + +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; + +@FeignClient( + name = "KakaoInfoClient", + url = "${feign.client.kakao.oicd-base-url}") +public interface KakaoInfoClient { + + @GetMapping("${feign.client.kakao.oicd-userinfo-uri}") + KakaoInformationResponse kakaoUserInfo(@RequestHeader("Authorization") String accessToken); +} \ No newline at end of file From d28d7f836c570f143f1724358a95ec9af37af406 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:28:20 +0900 Subject: [PATCH 08/17] =?UTF-8?q?#29=20feat:=20KakaoInformationResponse=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자 정보 가져오기 API를 통한 응답을 받기 위한 DTO 구현 --- .../auth/KakaoInformationResponse.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoInformationResponse.java diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoInformationResponse.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoInformationResponse.java new file mode 100644 index 0000000..cfeea39 --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoInformationResponse.java @@ -0,0 +1,13 @@ +package com.example.pnuunivmiryangcampus.auth; + +public record KakaoInformationResponse( + String sub, + String nickname, + String email, + boolean emailVerified + ) { + + public static KakaoInformationResponse of(String sub, String nickname, String email, boolean emailVerified) { + return new KakaoInformationResponse(sub, nickname, email, emailVerified); + } +} From 8bced906cc42ace23612fea55826f0ae61b5186c Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:28:42 +0900 Subject: [PATCH 09/17] =?UTF-8?q?#29=20feat:=20oicdOpenKeyUri=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/pnuunivmiryangcampus/auth/KakaoProperties.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoProperties.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoProperties.java index 4d06dd7..06dbbbf 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoProperties.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/KakaoProperties.java @@ -13,6 +13,7 @@ public class KakaoProperties { private String baseUrl; private String authUrl; private String tokenUri; + private String oicdOpenKeyUri; private String restApiKey; private String redirectUri; private String grantType; From 83c29a301230b58749e466041dcb69da0d929592 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:29:46 +0900 Subject: [PATCH 10/17] =?UTF-8?q?#29=20chore:=20ID=20=ED=86=A0=ED=81=B0=20?= =?UTF-8?q?=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=A6=9D=EC=9D=84=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20JJWT=20=EB=9D=BC=EC=9D=B4=EB=B8=8C?= =?UTF-8?q?=EB=9F=AC=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.gradle b/build.gradle index d043bfb..46c0de2 100644 --- a/build.gradle +++ b/build.gradle @@ -31,11 +31,14 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' + implementation 'io.jsonwebtoken:jjwt-api:0.12.5' implementation 'org.springframework.boot:spring-boot-starter-data-redis' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' + runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' annotationProcessor 'org.projectlombok:lombok' annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" testImplementation 'org.springframework.boot:spring-boot-starter-test' From 6c5af6d527b51cf6935042aece1c649967021330 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:31:13 +0900 Subject: [PATCH 11/17] =?UTF-8?q?#29=20feat:=20OIDCDecodePayload=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ID 토큰 유효성 검증을 통과한 토큰의 Payload를 받는 DTO 구현 --- .../auth/OIDCDecodePayload.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCDecodePayload.java diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCDecodePayload.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCDecodePayload.java new file mode 100644 index 0000000..88d367a --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCDecodePayload.java @@ -0,0 +1,16 @@ +package com.example.pnuunivmiryangcampus.auth; + +public record OIDCDecodePayload( + /* issuer ex https://kauth.kakao.com */ + String iss, + /* client id */ + String aud, + /* oauth provider account unique id */ + String sub, + String email +) { + + public static OIDCDecodePayload of(String iss, String aud, String sub, String email) { + return new OIDCDecodePayload(iss, aud, sub, email); + } +} From 41a66450be0a6b32e55fb31bbd11e10cc5545b0b Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:32:57 +0900 Subject: [PATCH 12/17] =?UTF-8?q?#29=20feat:=20OIDCPublicKeyDto=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 공개키 목록을 받는 DTO 구현 --- .../auth/OIDCPublicKeyDto.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCPublicKeyDto.java diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCPublicKeyDto.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCPublicKeyDto.java new file mode 100644 index 0000000..8b769cc --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCPublicKeyDto.java @@ -0,0 +1,14 @@ +package com.example.pnuunivmiryangcampus.auth; + +public record OIDCPublicKeyDto( + String kid, + String alg, + String use, + String n, + String e +) { + + public static OIDCPublicKeyDto of(String kid, String alg, String use, String n, String e) { + return new OIDCPublicKeyDto(kid, alg, use, n, e); + } +} From 812126857cda3fd77be14ba3f676cb40340ac3a8 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:33:53 +0900 Subject: [PATCH 13/17] =?UTF-8?q?#29=20feat:=20OIDCPublicKeysResponse=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 공개키 목록이 최소 2개 이상이기 때문에 List 형식으로 DTO 구현 --- .../auth/OIDCPublicKeysResponse.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCPublicKeysResponse.java diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCPublicKeysResponse.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCPublicKeysResponse.java new file mode 100644 index 0000000..7915f45 --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/OIDCPublicKeysResponse.java @@ -0,0 +1,12 @@ +package com.example.pnuunivmiryangcampus.auth; + +import java.util.List; + +public record OIDCPublicKeysResponse( + List keys +) { + + public static OIDCPublicKeysResponse of(List keys) { + return new OIDCPublicKeysResponse(keys); + } +} \ No newline at end of file From fb92bbdffdea54968529d5abf26d3cd148273c27 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:37:52 +0900 Subject: [PATCH 14/17] =?UTF-8?q?#29=20feat:=20JwtOIDCProvider=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - id 토큰 header를 base64로 디코딩해 kid 값을 리턴하는 getKidFromTokenHeader 구현 - OIDCPublicKeyDto를 통해 받은 n, e 변수를 통해 RSA 공개키 변수를 리턴하는 getRSAPublicKey 구현 - ID 토큰의 페이로드 값 검증과 서명 검증을 진행하는 getOIDCTokenJws 구현 - 검증 완료된 ID 토큰의 payload를 OIDCDecodePayload로 담아 리턴하는 getOIDCTokenBody 구현 --- .../auth/Exception500.java | 10 +++ .../auth/JwtOIDCProvider.java | 79 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/auth/Exception500.java create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/auth/JwtOIDCProvider.java diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/Exception500.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/Exception500.java new file mode 100644 index 0000000..0516fcf --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/Exception500.java @@ -0,0 +1,10 @@ +package com.example.pnuunivmiryangcampus.auth; + +import lombok.Getter; + +@Getter +public class Exception500 extends RuntimeException { + public Exception500(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/JwtOIDCProvider.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/JwtOIDCProvider.java new file mode 100644 index 0000000..f29f050 --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/JwtOIDCProvider.java @@ -0,0 +1,79 @@ +package com.example.pnuunivmiryangcampus.auth; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPublicKeySpec; +import java.util.Base64; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.configurationprocessor.json.JSONException; +import org.springframework.boot.configurationprocessor.json.JSONObject; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class JwtOIDCProvider { + + public String getKidFromTokenHeader(String token) { + + String KID = "kid"; + String[] splitToken = token.split("\\."); + String header = splitToken[0]; + + byte[] decodeJson = Base64.getDecoder().decode(header); + String decodeHeader = new String(decodeJson); + + try { + JSONObject jsonObject = new JSONObject(decodeHeader); + return jsonObject.get(KID).toString(); + } catch (JSONException e) { + return e.toString(); + } + } + + public Jws getOIDCTokenJws(String token, String modulus, String exponent, String iss, String aud) { + + try { + return Jwts.parser() + .verifyWith(getRSAPublicKey(modulus, exponent)) + .requireAudience(aud) + .requireIssuer(iss) + .build() + .parseSignedClaims(token); + } catch (ExpiredJwtException e) { + throw new Exception500(e.getMessage()); + } catch (Exception e) { + log.error(e.toString()); + throw new Exception500(e.getMessage()); + } + } + + public OIDCDecodePayload getOIDCTokenBody(String token, String modulus, String exponent, String iss, String aud) { + + Claims payload = getOIDCTokenJws(token, modulus, exponent, iss, aud).getPayload(); + + return new OIDCDecodePayload( + payload.getIssuer(), + payload.getAudience().toString(), + payload.getSubject(), + payload.get("email", String.class)); + } + + private PublicKey getRSAPublicKey(String modulus, String exponent) throws NoSuchAlgorithmException, InvalidKeySpecException { + + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + byte[] decodeN = Base64.getUrlDecoder().decode(modulus); + byte[] decodeE = Base64.getUrlDecoder().decode(exponent); + BigInteger n = new BigInteger(1, decodeN); + BigInteger e = new BigInteger(1, decodeE); + + RSAPublicKeySpec keySpec = new RSAPublicKeySpec(n, e); + return keyFactory.generatePublic(keySpec); + } +} From c299ed56c5df3f7a87d37654dd4241e98f13c8ed Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:53:12 +0900 Subject: [PATCH 15/17] =?UTF-8?q?#29=20feat:=20OauthOIDCHelper=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - id 토큰의 kid 값으로 공개키 목록을 조회해 해당하는 n, e 값을 전달해서 유효성 검증 후 decode된 payload를 리턴하는 getOIDCDecodePayload 구현 - 공개키 목록을 조회해서 decode된 payload를 리턴하는 getKakaoOIDCDecodePayload 구현 --- .../auth/OauthOIDCHelper.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/main/java/com/example/pnuunivmiryangcampus/auth/OauthOIDCHelper.java diff --git a/src/main/java/com/example/pnuunivmiryangcampus/auth/OauthOIDCHelper.java b/src/main/java/com/example/pnuunivmiryangcampus/auth/OauthOIDCHelper.java new file mode 100644 index 0000000..25b9198 --- /dev/null +++ b/src/main/java/com/example/pnuunivmiryangcampus/auth/OauthOIDCHelper.java @@ -0,0 +1,34 @@ +package com.example.pnuunivmiryangcampus.auth; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class OauthOIDCHelper { + + private final JwtOIDCProvider jwtOIDCProvider; + private final KakaoOauthClient kakaoOauthClient; + private final KakaoProperties kakaoProperties; + + private OIDCDecodePayload getPayloadFromIdToken(String token, String iss, String aud, OIDCPublicKeysResponse oidcPublicKeysResponse) { + String kid = jwtOIDCProvider.getKidFromTokenHeader(token); + + OIDCPublicKeyDto oidcPublicKeyDto = oidcPublicKeysResponse.keys().stream() + .filter(o -> o.kid().equals(kid)) + .findFirst() + .orElseThrow(); + + return jwtOIDCProvider.getOIDCTokenBody(token, oidcPublicKeyDto.n(), oidcPublicKeyDto.e(), iss, aud); + } + + public OIDCDecodePayload getKakaoOIDCDecodePayload(String token) { + + OIDCPublicKeysResponse oidcPublicKeysResponse = kakaoOauthClient.getKakaoOIDCOpenKeys(); + return getPayloadFromIdToken( + token, + kakaoProperties.getBaseUrl(), + kakaoProperties.getRestApiKey(), + oidcPublicKeysResponse); + } +} From 81eb4047267fead28e7cbf0017199f714e51dc5c Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:54:30 +0900 Subject: [PATCH 16/17] =?UTF-8?q?#29=20feat:=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 유저 정보가 있는 지 확인 후 없으면 id 토큰을 통해 user 정보를 가져와 user_account table에 추가하는 기능 구현 --- .../service/LoginService.java | 38 +++++++++++++++++-- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/service/LoginService.java b/src/main/java/com/example/pnuunivmiryangcampus/service/LoginService.java index e88b6e9..b33edd8 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/service/LoginService.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/service/LoginService.java @@ -1,26 +1,58 @@ package com.example.pnuunivmiryangcampus.service; -import com.example.pnuunivmiryangcampus.auth.KakaoApiCaller; +import com.example.pnuunivmiryangcampus.auth.KakaoInfoClient; +import com.example.pnuunivmiryangcampus.auth.KakaoInformationResponse; +import com.example.pnuunivmiryangcampus.auth.KakaoOauthClient; import com.example.pnuunivmiryangcampus.auth.KakaoProperties; +import com.example.pnuunivmiryangcampus.auth.OIDCDecodePayload; +import com.example.pnuunivmiryangcampus.auth.OauthOIDCHelper; +import com.example.pnuunivmiryangcampus.domain.UserAccount; import com.example.pnuunivmiryangcampus.dto.KakaoTokenDto; +import com.example.pnuunivmiryangcampus.dto.UserAccountDto; +import com.example.pnuunivmiryangcampus.repository.UserAccountRepository; +import java.util.Optional; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +@Slf4j @RequiredArgsConstructor @Transactional @Service public class LoginService { - private final KakaoApiCaller kakaoApiCaller; + private final KakaoOauthClient kakaoOauthClient; + private final KakaoInfoClient kakaoInfoClient; private final KakaoProperties kakaoProperties; + private final OauthOIDCHelper oauthOIDCHelper; + private final UserAccountRepository userAccountRepository; public KakaoTokenDto getKakaoToken(String code) { - return kakaoApiCaller.getKakaoToken( + + return kakaoOauthClient.getKakaoToken( kakaoProperties.getRestApiKey(), kakaoProperties.getRedirectUri(), code, kakaoProperties.getGrantType() ); } + + public void isUserRegistered(KakaoTokenDto kakaoTokenDto) { + + OIDCDecodePayload oidcDecodePayload = oauthOIDCHelper.getKakaoOIDCDecodePayload(kakaoTokenDto.idToken()); + Optional userAccount = userAccountRepository.findBySub(oidcDecodePayload.sub()); + + if (userAccount.isEmpty()) { + saveUserAccount(kakaoTokenDto); + } + } + + private void saveUserAccount(KakaoTokenDto kakaoTokenDto) { + + KakaoInformationResponse kakaoInformationResponse = kakaoInfoClient.kakaoUserInfo(kakaoTokenDto.tokenType() + " " + kakaoTokenDto.accessToken()); + UserAccountDto userAccountDto = UserAccountDto.of(kakaoInformationResponse.nickname(), kakaoInformationResponse.email(), kakaoInformationResponse.sub()); + + userAccountRepository.save(userAccountDto.toEntity()); + } } From f0db47a3846ac157fe8ef1d2a3c271e0db3a0022 Mon Sep 17 00:00:00 2001 From: KimSehoon Date: Sun, 17 Mar 2024 22:55:40 +0900 Subject: [PATCH 17/17] =?UTF-8?q?#29=20refactor:=20getKakaoToken=EC=97=90?= =?UTF-8?q?=20=ED=9A=8C=EC=9B=90=20=EA=B0=80=EC=9E=85=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pnuunivmiryangcampus/controller/LoginController.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/pnuunivmiryangcampus/controller/LoginController.java b/src/main/java/com/example/pnuunivmiryangcampus/controller/LoginController.java index 4e48f0f..4387d38 100644 --- a/src/main/java/com/example/pnuunivmiryangcampus/controller/LoginController.java +++ b/src/main/java/com/example/pnuunivmiryangcampus/controller/LoginController.java @@ -25,6 +25,10 @@ public String kakaoLogin() { @GetMapping("/kakao/callback") public ResponseEntity getKakaoToken(@RequestParam String code) { - return ResponseEntity.ok(loginService.getKakaoToken(code)); + + KakaoTokenDto kakaoTokenDto = loginService.getKakaoToken(code); + loginService.isUserRegistered(kakaoTokenDto); + + return ResponseEntity.ok(kakaoTokenDto); } }