Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] 일반 로그인을 구현한다. #775

Merged
merged 28 commits into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bca3bf1
feat: user 필드 추가에 따른 sql 수정
shin-jisong Oct 7, 2024
b44cc92
feat(UserRepository): 이메일과 로그인 타입으로 조회 구현
shin-jisong Oct 10, 2024
5cc7c23
feat(User): 비밀번호 불일치 확인 구현
shin-jisong Oct 10, 2024
c90960d
feat(PasswordEncoder): 비밀번호 암호화 구현
shin-jisong Oct 10, 2024
a790116
fix(UserRepository): findByEmailAndLoginType 쿼리문 오류 수정
shin-jisong Oct 10, 2024
22b26c2
feat(AuthService): 로컬 로그인 구현
shin-jisong Oct 10, 2024
e488edc
feat(AuthController): 로컬 로그인 구현
shin-jisong Oct 10, 2024
8a63fa9
style: 코드 재정렬
shin-jisong Oct 10, 2024
38eac07
Merge branch 'refs/heads/dev-be' into feat/755-local-login
shin-jisong Oct 10, 2024
e680d8e
test: 충돌 해결
shin-jisong Oct 10, 2024
0dc0147
Merge branch 'refs/heads/dev-be' into feat/755-local-login
shin-jisong Oct 11, 2024
08b86b6
fix: 충돌 해결
shin-jisong Oct 11, 2024
4419c2e
test: 깨진 테스트 수정
shin-jisong Oct 11, 2024
5fa12f4
feat(AuthService): localLogin 수정 구현
shin-jisong Oct 11, 2024
005aeb6
feat(ArticleRepository): 시간이 같을 경우, 아이디로 정렬
shin-jisong Oct 11, 2024
4472507
feat(PasswordEncoder): 암호화 구현
shin-jisong Oct 11, 2024
8f2dcd4
feat(ChecklistRepository): 시간이 같을 경우, id로 정렬
shin-jisong Oct 11, 2024
c37e5c1
feat(Password): isDifferent 구현
shin-jisong Oct 11, 2024
2d1d5bc
feat(User): isDifferent 구현
shin-jisong Oct 11, 2024
6dd181c
test: 깨지는 테스트 수정
shin-jisong Oct 11, 2024
b2da013
style: 코드 재정렬
shin-jisong Oct 11, 2024
53e3204
style: oauth 명명 변경
shin-jisong Oct 11, 2024
bd4c012
style: 함수 순서 변경
shin-jisong Oct 11, 2024
fb3b2a1
feat(PasswordEncoder): 상수화
shin-jisong Oct 12, 2024
7c465e3
feat(Password): 비어있을 시 null 처리
shin-jisong Oct 12, 2024
3e717e4
feat(Password): null이 들어오면 예외 발생
shin-jisong Oct 14, 2024
b21c9af
feat(AuthController): 로그인 path 변경
shin-jisong Oct 14, 2024
6859f83
test(AuthE2ETest): 로컬 로그인 path 변경
shin-jisong Oct 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ default Article getById(Long id) {

@Query("SELECT a FROM Article a " +
"WHERE a.deleted = false " +
"ORDER BY a.createdAt DESC ")
"ORDER BY a.createdAt DESC, a.id DESC")
List<Article> findLatestArticles();

@Modifying(flushAutomatically = true, clearAutomatically = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.bang_ggood.auth.config.AuthRequiredPrincipal;
import com.bang_ggood.auth.controller.cookie.CookieProvider;
import com.bang_ggood.auth.controller.cookie.CookieResolver;
import com.bang_ggood.auth.dto.request.LocalLoginRequestV1;
import com.bang_ggood.auth.dto.request.OauthLoginRequest;
import com.bang_ggood.auth.dto.request.RegisterRequestV1;
import com.bang_ggood.auth.dto.response.AuthTokenResponse;
Expand Down Expand Up @@ -36,8 +37,21 @@ public ResponseEntity<Void> register(@Valid @RequestBody RegisterRequestV1 reque
}

@PostMapping("/oauth/login")
public ResponseEntity<Void> login(@Valid @RequestBody OauthLoginRequest request) {
AuthTokenResponse response = authService.login(request);
public ResponseEntity<Void> oauthLogin(@Valid @RequestBody OauthLoginRequest request) {
AuthTokenResponse response = authService.oauthLogin(request);

ResponseCookie accessTokenCookie = cookieProvider.createAccessTokenCookie(response.accessToken());
ResponseCookie refreshTokenCookie = cookieProvider.createRefreshTokenCookie(response.refreshToken());

return ResponseEntity.ok()
.header(HttpHeaders.SET_COOKIE, accessTokenCookie.toString())
.header(HttpHeaders.SET_COOKIE, refreshTokenCookie.toString())
.build();
}

@PostMapping("/v1/local-auth/login")
public ResponseEntity<Void> localLogin(@Valid @RequestBody LocalLoginRequestV1 request) {
AuthTokenResponse response = authService.localLogin(request);

ResponseCookie accessTokenCookie = cookieProvider.createAccessTokenCookie(response.accessToken());
ResponseCookie refreshTokenCookie = cookieProvider.createRefreshTokenCookie(response.refreshToken());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.bang_ggood.auth.dto.request;

import jakarta.validation.constraints.NotBlank;

public record LocalLoginRequestV1(@NotBlank(message = "이메일이 존재하지 않습니다.") String email,
@NotBlank(message = "비밀번호가 존재하지 않습니다.") String password) {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.bang_ggood.auth.service;

import com.bang_ggood.auth.dto.request.LocalLoginRequestV1;
import com.bang_ggood.auth.dto.request.OauthLoginRequest;
import com.bang_ggood.auth.dto.request.RegisterRequestV1;
import com.bang_ggood.auth.dto.response.AuthTokenResponse;
Expand Down Expand Up @@ -34,7 +35,7 @@ public class AuthService {
private final JwtTokenProvider jwtTokenProvider;
private final JwtTokenResolver jwtTokenResolver;
private final DefaultChecklistService defaultChecklistService;
private final UserRepository userRepository; // TODO 리팩토링
private final UserRepository userRepository;

@Transactional
public Long register(RegisterRequestV1 request) {
Expand All @@ -46,17 +47,36 @@ public Long register(RegisterRequestV1 request) {
}

@Transactional
public AuthTokenResponse login(OauthLoginRequest request) {
public AuthTokenResponse oauthLogin(OauthLoginRequest request) {
OauthInfoApiResponse oauthInfoApiResponse = oauthClient.requestOauthInfo(request);

User user = userRepository.findByEmail(new Email(oauthInfoApiResponse.kakao_account().email()))
User user = userRepository.findByEmailAndLoginType(new Email(oauthInfoApiResponse.kakao_account().email()),
LoginType.KAKAO)
.orElseGet(() -> signUp(oauthInfoApiResponse));

String accessToken = jwtTokenProvider.createAccessToken(user);
String refreshToken = jwtTokenProvider.createRefreshToken(user);
return AuthTokenResponse.of(accessToken, refreshToken);
}

@Transactional(readOnly = true)
public AuthTokenResponse localLogin(LocalLoginRequestV1 request) {
User user = userRepository.findByEmailAndLoginType(new Email(request.email()), LoginType.LOCAL)
.orElseThrow(() -> new BangggoodException(ExceptionCode.USER_NOT_FOUND));
checkPassword(request, user);

String accessToken = jwtTokenProvider.createAccessToken(user);
String refreshToken = jwtTokenProvider.createRefreshToken(user);
return AuthTokenResponse.of(accessToken, refreshToken);
}


private void checkPassword(LocalLoginRequestV1 request, User user) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private void checkPassword(LocalLoginRequestV1 request, User user) {
private void validatePassword(LocalLoginRequestV1 request, User user) {

지금까지는 검증 메서드를 validate라고 했던 것 같아서 제안드려봅니다~!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 부분은 정책에 따라 규칙에 맞는가 확인하는 것이 아닌 맞는가 체크하는 부분이라 생각해서 validate 명명보다는 비즈니스 로직 명명을 가질 수 있도록 구현하였습니다!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 이해한 바에 따르면, 단순히 비밀번호가 다른지 체크하는 부분은 정책적인 부분이 아니라 네이밍을 다르게 가져가고 싶다는 의미로 이해했어요! 하지만 null, empty 체크도 비슷한 경우라고 생각되는데 validate 메서드명을 사용했던 것 같아서 이 부분은 어떻게 생각하는지 궁금합니다 ~

Copy link
Contributor Author

@shin-jisong shin-jisong Oct 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null 혹은 empty 체크는 값 자체의 형식에 대한 검증이라 생각해요!
validate 검증 로직은 주로 입력 데이터가 특정 형식, 패턴 또는 규칙에 부합하는지 확인 등 비즈니스 로직을 시작하기 직전에 값을 선별하는 데 사용하는 명명에 가깝다고 생각해요
예를 들어 저장한다는 비즈니스 로직 전 해당 값을 저장하기에 유효한지 검증하는 validate 검증 로직을 작성하는 것처럼요 🤔

반면에 비밀번호 일치 여부를 확인하는 로직은 단순히 입력 데이터의 형식 검증이 아닌, 기존 데이터와 비교하여 중요한 비즈니스 결정을 내리는 과정이라 생각했어요!
validate라는 검증의 의미만 담기에는 다소 의미가 축소되는 느낌이 있다고 판단하였습니다

if (user.isDifferent(request.password())) {
throw new BangggoodException(ExceptionCode.USER_INVALID_PASSWORD);
}
}

private User signUp(OauthInfoApiResponse oauthInfoApiResponse) {
User user = userRepository.save(oauthInfoApiResponse.toUserEntity());
defaultChecklistService.createDefaultChecklistAndQuestions(user);
Expand Down Expand Up @@ -84,15 +104,6 @@ public void logout(String accessToken, String refreshToken, User user) {
validateTokenOwnership(user, accessAuthUser, refreshAuthUser);
}

private static void validateTokenOwnership(User user, AuthUser accessAuthUser, AuthUser refreshAuthUser) {
if (!accessAuthUser.id().equals(refreshAuthUser.id())) {
throw new BangggoodException(ExceptionCode.AUTHENTICATION_TOKEN_USER_MISMATCH);
}
if (!user.getId().equals(accessAuthUser.id())) {
throw new BangggoodException(ExceptionCode.AUTHENTICATION_TOKEN_NOT_OWNED_BY_USER);
}
}

@Transactional(readOnly = true)
public User getAuthUser(String token) {
AuthUser authUser = jwtTokenResolver.resolveAccessToken(token);
Expand All @@ -107,4 +118,13 @@ public String reissueAccessToken(String refreshToken) {
User user = userRepository.getUserById(authUser.id());
return jwtTokenProvider.createAccessToken(user);
}

private static void validateTokenOwnership(User user, AuthUser accessAuthUser, AuthUser refreshAuthUser) {
if (!accessAuthUser.id().equals(refreshAuthUser.id())) {
throw new BangggoodException(ExceptionCode.AUTHENTICATION_TOKEN_USER_MISMATCH);
}
if (!user.getId().equals(accessAuthUser.id())) {
throw new BangggoodException(ExceptionCode.AUTHENTICATION_TOKEN_NOT_OWNED_BY_USER);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@
public class PasswordEncoder {

private static final String DELIMITER = ":";
private static final int PASSWORD_AND_SALT_LENGTH = 2;

private PasswordEncoder() {
}

public static String encodeWithGeneralSalt(String password) {
return encode(password, getSalt());
}

public static String encode(String password, byte[] salt) {
public static String encodeWithSpecificSalt(String password, String passwordWithSalt) {
return encode(password, extractSaltByPassword(passwordWithSalt));
}

private static String encode(String password, byte[] salt) {
try {
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 512);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
Expand All @@ -31,13 +39,20 @@ public static String encode(String password, byte[] salt) {
}
}

public static byte[] getSalt() {
private static byte[] getSalt() {
SecureRandom secureRandom = new SecureRandom();
byte[] salt = new byte[64];
secureRandom.nextBytes(salt);
return salt;
}

private PasswordEncoder() {
private static byte[] extractSaltByPassword(String encodedPassword) {
String[] parts = encodedPassword.split(DELIMITER);
if (parts.length != PASSWORD_AND_SALT_LENGTH) {
throw new BangggoodException(ExceptionCode.PASSWORD_HASHING_ERROR);
}

String encodedSalt = parts[1];
return Base64.getDecoder().decode(encodedSalt);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import com.bang_ggood.auth.config.UserPrincipal;
import com.bang_ggood.checklist.dto.request.ChecklistRequest;
import com.bang_ggood.checklist.dto.request.ChecklistRequestV1;
import com.bang_ggood.checklist.dto.response.SelectedChecklistResponse;
import com.bang_ggood.checklist.dto.response.ChecklistsPreviewResponse;
import com.bang_ggood.checklist.dto.response.SelectedChecklistResponse;
import com.bang_ggood.checklist.dto.response.SelectedChecklistResponseV1;
import com.bang_ggood.checklist.service.ChecklistManageService;
import com.bang_ggood.checklist.service.ChecklistService;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public record SelectedChecklistResponseV1(SelectedRoomResponseV1 room,
public static SelectedChecklistResponseV1 of(SelectedRoomResponse room, List<SelectedOptionResponse> options,
List<SelectedCategoryQuestionsResponse> categories, boolean isLiked,
SubwayStationResponses stations) {
return new SelectedChecklistResponseV1(SelectedRoomResponseV1.from(room), options, categories, isLiked, stations);
return new SelectedChecklistResponseV1(SelectedRoomResponseV1.from(room), options, categories, isLiked,
stations);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ default Checklist getById(@Param("id") Long id) {
@Query("SELECT c FROM Checklist c "
+ "WHERE c.user = :user "
+ "AND c.deleted = false "
+ "ORDER BY c.createdAt DESC ")
+ "ORDER BY c.createdAt DESC, c.id DESC ")
List<Checklist> findAllByUserOrderByLatest(@Param("user") User user);

@Query("SELECT c FROM Checklist c "
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.bang_ggood.global.config;

import com.bang_ggood.auth.config.AuthRequiredPrincipalArgumentResolver;
import com.bang_ggood.auth.controller.cookie.CookieResolver;
import com.bang_ggood.auth.config.UserPrincipalArgumentResolver;
import com.bang_ggood.auth.controller.cookie.CookieResolver;
import com.bang_ggood.auth.service.AuthService;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public enum ExceptionCode {

// User
USER_NOT_FOUND(HttpStatus.UNAUTHORIZED, "유저가 존재하지 않습니다."),
USER_INVALID_PASSWORD(HttpStatus.BAD_REQUEST, "잘못된 비밀번호입니다."),
USER_EMAIL_ALREADY_USED(HttpStatus.CONFLICT, "이미 해당 이메일을 사용하는 유저가 존재합니다."),
GUEST_USER_NOT_FOUND(HttpStatus.INTERNAL_SERVER_ERROR, "게스트 유저가 존재하지 않습니다."),
GUEST_USER_UNEXPECTED_EXIST(HttpStatus.INTERNAL_SERVER_ERROR, "예상치 못한 게스트 유저가 존재합니다. 데이터베이스를 확인해주세요."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ public record SelectedRoomResponse(String roomName, Integer deposit, Integer ren
String realEstate,
Double size, String floorLevel, String structure,
Integer occupancyMonth, String occupancyPeriod, String memo, String summary,
List<Integer> includedMaintenances, Integer maintenanceFee, LocalDateTime createdAt) {
List<Integer> includedMaintenances, Integer maintenanceFee,
LocalDateTime createdAt) {

public static SelectedRoomResponse of(Checklist checklist, List<Integer> includedMaintenances) {
return new SelectedRoomResponse(checklist.getRoomName(), checklist.getDeposit(), checklist.getRent(),
Expand All @@ -18,6 +19,7 @@ public static SelectedRoomResponse of(Checklist checklist, List<Integer> include
checklist.getRoomStation(), checklist.getRoomWalkingTime(), checklist.getRealEstate(),
checklist.getRoomSize(), checklist.getRoomFloorLevel().getName(),
checklist.getRoomStructure().getName(), checklist.getOccupancyMonth(), checklist.getOccupancyPeriod(),
checklist.getMemo(), checklist.getSummary(), includedMaintenances, checklist.getMaintenanceFee(), checklist.getCreatedAt());
checklist.getMemo(), checklist.getSummary(), includedMaintenances, checklist.getMaintenanceFee(),
checklist.getCreatedAt());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@
import java.time.LocalDateTime;
import java.util.List;

public record SelectedRoomResponseV1(String roomName, Integer deposit, Integer rent, Integer contractTerm, Integer floor,
public record SelectedRoomResponseV1(String roomName, Integer deposit, Integer rent, Integer contractTerm,
Integer floor,
String address, String buildingName, String realEstate,
Double size, String floorLevel, String structure,
Integer occupancyMonth, String occupancyPeriod, String memo, String summary,
List<Integer> includedMaintenances, Integer maintenanceFee, LocalDateTime createdAt) {
List<Integer> includedMaintenances, Integer maintenanceFee,
LocalDateTime createdAt) {

public static SelectedRoomResponseV1 from(SelectedRoomResponse response) {
return new SelectedRoomResponseV1(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public class SubwayReader {
public static List<SubwayStation> readSubwayStationData() {
List<SubwayStation> stations = new ArrayList<>();
try (CSVReader csvReader = new CSVReaderBuilder(
new InputStreamReader(getSubwayStationResource().getInputStream(), Charset.forName("EUC-KR"))).build()) {
new InputStreamReader(getSubwayStationResource().getInputStream(),
Charset.forName("EUC-KR"))).build()) {
String[] line = csvReader.readNext(); // drop first row
while ((line = csvReader.readNext()) != null) {
SubwayStation station = new SubwayStation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,12 @@ public ChecklistStation(Checklist checklist, String stationName, String stationL

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
ChecklistStation that = (ChecklistStation) o;
return Objects.equals(id, that.id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ public class SubwayStationResponse {
public static SubwayStationResponse of(SubwayStation station, double latitude, double longitude) {
List<String> stationLine = new ArrayList<>();
stationLine.add(station.getLine());
return new SubwayStationResponse(station.getName(), stationLine, station.calculateWalkingTime(latitude, longitude));
return new SubwayStationResponse(station.getName(), stationLine,
station.calculateWalkingTime(latitude, longitude));
}

public static SubwayStationResponse from(ChecklistStation checklistStation) {
List<String> stationLine = new ArrayList<>();
stationLine.add(checklistStation.getStationLine());
return new SubwayStationResponse(checklistStation.getStationName(), stationLine, checklistStation.getWalkingTime());
return new SubwayStationResponse(checklistStation.getStationName(), stationLine,
checklistStation.getWalkingTime());
}

public SubwayStationResponse merge(SubwayStationResponse response) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ public class ChecklistStationService {

@Transactional
public void createChecklistStations(Checklist checklist, double latitude, double longitude) {
List<SubwayStationResponse> responses = subwayStationService.readNearestStation(latitude, longitude).getStations();
List<SubwayStationResponse> responses = subwayStationService.readNearestStation(latitude, longitude)
.getStations();
List<ChecklistStation> checklistStations = new ArrayList<>();

for (SubwayStationResponse response : responses) {
for (String stationLine : response.getStationLine()) {
checklistStations.add(new ChecklistStation(checklist, response.getStationName(), stationLine, response.getWalkingTime()));
checklistStations.add(new ChecklistStation(checklist, response.getStationName(), stationLine,
response.getWalkingTime()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public Email(String value) {
}

public void validateEmailPattern(String email) {
if(!EMAIL_PATTERN.matcher(email).matches()) {
if (!EMAIL_PATTERN.matcher(email).matches()) {
throw new BangggoodException(ExceptionCode.EMAIL_INVALID_FORMAT);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,13 @@ public Password(String value) {
this.value = PasswordEncoder.encodeWithGeneralSalt(value);
}

public void validatePasswordPattern(String password) {
if (!PASSWORD_PATTERN.matcher(password).matches()) {
public boolean isDifferent(String password) {
String targetPassword = PasswordEncoder.encodeWithSpecificSalt(password, value);
return !value.equals(targetPassword);
}

private void validatePasswordPattern(String password) {
if (password == null || !PASSWORD_PATTERN.matcher(password).matches()) {
throw new BangggoodException(ExceptionCode.PASSWORD_INVALID_FORMAT);
}
}
Expand All @@ -43,8 +48,8 @@ public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) {
return false;
}
Password password1 = (Password) o;
return Objects.equals(value, password1.value);
Password targetPassword = (Password) o;
return Objects.equals(value, targetPassword.value);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ public User(Long id, String name, String email) { // TODO 테스트용
this.email = new Email(email);
}

public boolean isDifferent(String targetPassword) {
return password.isDifferent(targetPassword);
}

@Override
public boolean equals(Object o) {
if (this == o) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ default User getUserById(Long id) {
@Query("SELECT u FROM User u WHERE u.userType = :userType and u.deleted = false ")
List<User> findUserByUserType(@Param("userType") UserType userType);

@Query("SELECT u FROM User u WHERE u.email = :email and u.deleted = false ")
Optional<User> findByEmail(@Param("email") Email email);
@Query("SELECT u FROM User u WHERE u.email = :email and u.loginType = :loginType and u.deleted = false")
Optional<User> findByEmailAndLoginType(@Param("email") Email email, @Param("loginType") LoginType loginType);

@Transactional
@Modifying(flushAutomatically = true, clearAutomatically = true)
Expand Down
3 changes: 2 additions & 1 deletion backend/bang-ggood/src/main/resources/data.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
-- 비밀번호 : password1234
INSERT INTO users(name, email, password, user_type, login_type, created_at, modified_at, deleted)
VALUES ('방방이', '[email protected]', 'xDNYKEJqE/36U0Dt3nXRMFPNEMEgjCYM7R/A4B29baOsv4KYQ9MGgcO3HUa11sNKCFb9ZXyYBqJqxNglvBzFvg==:7yejAszEpxBb7AyZNKvAqpmMEJiKFXIa8JKwAx3n4loB2DRcAC2pfwkgo/dzKzRvBX4RbrATWaIlPYrgAhbHZQ==',
VALUES ('방방이', '[email protected]',
'xDNYKEJqE/36U0Dt3nXRMFPNEMEgjCYM7R/A4B29baOsv4KYQ9MGgcO3HUa11sNKCFb9ZXyYBqJqxNglvBzFvg==:7yejAszEpxBb7AyZNKvAqpmMEJiKFXIa8JKwAx3n4loB2DRcAC2pfwkgo/dzKzRvBX4RbrATWaIlPYrgAhbHZQ==',
'USER', 'LOCAL', '2024-07-22 07:56:42', '2024-07-22 07:56:42', false);

INSERT INTO custom_checklist_question(user_id, question, created_at, modified_at, deleted)
Expand Down
Loading
Loading