diff --git a/build.gradle b/build.gradle index ee0c03b..46c0de2 100644 --- a/build.gradle +++ b/build.gradle @@ -31,10 +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' 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/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); + } +} 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 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); + } +} 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(); } 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; 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); + } +} 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); + } +} 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 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); + } +} 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 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); } } 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/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 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()); + } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0a28556..b9d9f22 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -29,17 +29,25 @@ spring: default-batch-fetch-size: 100 h2.console.enabled: true sql.init.mode: always + data: + redis: + port: 6379 + host: localhost 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://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 + oicd-base-url: https://kapi.kakao.com + oicd-userinfo-uri: /v1/oidc/userinfo + 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);