Skip to content

Commit 233724c

Browse files
authored
Merge pull request #55 from project-lyrics/SCRUM-189
device_id 검사 로직 추가
2 parents 32c8030 + fb08d2b commit 233724c

File tree

13 files changed

+250
-97
lines changed

13 files changed

+250
-97
lines changed

src/main/java/com/projectlyrics/server/domain/auth/api/AuthController.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,21 @@ public class AuthController {
2525

2626
@PostMapping("/sign-in")
2727
public ResponseEntity<AuthTokenResponse> signIn(
28-
@RequestBody @Valid AuthSignInRequest request
28+
@RequestBody @Valid AuthSignInRequest request,
29+
@RequestHeader("Device-Id") String deviceId
2930
) {
3031
return ResponseEntity
3132
.status(HttpStatus.OK)
32-
.body(authCommandService.signIn(request));
33+
.body(authCommandService.signIn(request, deviceId));
3334
}
3435

3536
@PostMapping("/sign-up")
3637
public ResponseEntity<AuthTokenResponse> signUp(
37-
@RequestBody @Valid AuthSignUpRequest request
38+
@RequestBody @Valid AuthSignUpRequest request,
39+
@RequestHeader("Device-Id") String deviceId
3840
) {
3941
return ResponseEntity
40-
.ok(authCommandService.signUp(request));
42+
.ok(authCommandService.signUp(request, deviceId));
4143
}
4244

4345
@PostMapping("/token")
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.projectlyrics.server.domain.auth.authentication.interceptor;
2+
3+
import com.projectlyrics.server.domain.auth.exception.NotRegisteredDeviceException;
4+
import com.projectlyrics.server.domain.auth.repository.AuthRepository;
5+
import jakarta.servlet.http.HttpServletRequest;
6+
import jakarta.servlet.http.HttpServletResponse;
7+
import lombok.RequiredArgsConstructor;
8+
import org.springframework.context.annotation.Profile;
9+
import org.springframework.stereotype.Component;
10+
import org.springframework.transaction.annotation.Transactional;
11+
import org.springframework.web.servlet.HandlerInterceptor;
12+
13+
@Profile({"dev", "local"})
14+
@Component
15+
@Transactional
16+
@RequiredArgsConstructor
17+
public class DeviceIdInterceptor implements HandlerInterceptor {
18+
19+
private final AuthRepository authRepository;
20+
21+
@Override
22+
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
23+
if (included(request)) {
24+
authRepository.findByDeviceId(request.getHeader("Device-Id"))
25+
.orElseThrow(NotRegisteredDeviceException::new);
26+
}
27+
28+
return true;
29+
}
30+
31+
private boolean included(HttpServletRequest request) {
32+
String requestURI = request.getRequestURI();
33+
return !requestURI.matches("/api/v1/auth/sign-in") &&
34+
!requestURI.matches("/api/v1/auth/sign-up");
35+
}
36+
}

src/main/java/com/projectlyrics/server/domain/auth/domain/Auth.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,31 @@ public class Auth {
2222
private AuthProvider authProvider;
2323
@Indexed
2424
private String refreshToken;
25+
@Indexed
26+
private String deviceId;
2527

2628
private Auth(
2729
String socialId,
2830
AuthProvider authProvider,
29-
String refreshToken
31+
String refreshToken,
32+
String deviceId
3033
) {
3134
this.socialId = socialId;
3235
this.authProvider = authProvider;
3336
this.refreshToken = refreshToken;
37+
this.deviceId = deviceId;
3438
}
3539

36-
public static Auth create(SocialInfo socialInfo, String refreshToken) {
40+
public static Auth create(
41+
SocialInfo socialInfo,
42+
String refreshToken,
43+
String deviceId
44+
) {
3745
return new Auth(
3846
socialInfo.getSocialId(),
3947
socialInfo.getAuthProvider(),
40-
refreshToken
48+
refreshToken,
49+
deviceId
4150
);
4251
}
4352
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.projectlyrics.server.domain.auth.exception;
2+
3+
import com.projectlyrics.server.domain.common.message.ErrorCode;
4+
import com.projectlyrics.server.global.exception.FeelinException;
5+
6+
public class NotRegisteredDeviceException extends FeelinException {
7+
8+
public NotRegisteredDeviceException() {
9+
super(ErrorCode.NOT_REGISTERED_DEVICE);
10+
}
11+
}

src/main/java/com/projectlyrics/server/domain/auth/repository/AuthRepository.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
public interface AuthRepository extends CrudRepository<Auth, String> {
99

1010
Optional<Auth> findByRefreshToken(String refreshToken);
11+
Optional<Auth> findByDeviceId(String deviceId);
1112
}

src/main/java/com/projectlyrics/server/domain/auth/service/AuthCommandService.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ public class AuthCommandService {
4141
private final LikeCommandRepository likeCommandRepository;
4242
private final NotificationCommandRepository notificationCommandRepository;
4343

44-
public AuthTokenResponse signUp(AuthSignUpRequest request) {
44+
public AuthTokenResponse signUp(AuthSignUpRequest request, String deviceId) {
4545
SocialInfo socialInfo = authQueryService.getSocialInfo(AuthGetSocialInfo.from(request));
4646
checkIfAlreadyExists(socialInfo);
4747

4848
User user = userCommandRepository.save(User.create(UserCreate.of(socialInfo, request)));
4949

50-
AuthToken authToken = issueAndSaveToken(user);
50+
AuthToken authToken = issueAndSaveToken(user, deviceId);
5151
return AuthTokenResponse.of(authToken, user.getId());
5252
}
5353

@@ -60,12 +60,12 @@ else if (userQueryRepository.existsBySocialInfoAndForceDelete(socialInfo)) {
6060
}
6161
}
6262

63-
public AuthTokenResponse signIn(AuthSignInRequest request) {
63+
public AuthTokenResponse signIn(AuthSignInRequest request, String deviceId) {
6464
SocialInfo socialInfo = authQueryService.getSocialInfo(AuthGetSocialInfo.from(request));
6565
User user = userQueryRepository.findBySocialIdAndAuthProvider(socialInfo.getSocialId(), socialInfo.getAuthProvider())
6666
.orElseThrow(UserNotFoundException::new);
6767

68-
AuthToken authToken = issueAndSaveToken(user);
68+
AuthToken authToken = issueAndSaveToken(user, deviceId);
6969
return AuthTokenResponse.of(authToken, user.getId());
7070
}
7171

@@ -75,13 +75,13 @@ public AuthTokenResponse reissueToken(String refreshToken) {
7575
User user = userQueryRepository.findBySocialIdAndAuthProvider(auth.getSocialId(), auth.getAuthProvider())
7676
.orElseThrow(UserNotFoundException::new);
7777

78-
AuthToken authToken = issueAndSaveToken(user);
78+
AuthToken authToken = issueAndSaveToken(user, auth.getDeviceId());
7979
return AuthTokenResponse.of(authToken, user.getId());
8080
}
8181

82-
private AuthToken issueAndSaveToken(User user) {
82+
private AuthToken issueAndSaveToken(User user, String deviceId) {
8383
AuthToken authToken = jwtProvider.issueTokens(user.getId(), user.getNickname().getValue(), user.getRole());
84-
authRepository.save(Auth.create(user.getSocialInfo(), authToken.refreshToken()));
84+
authRepository.save(Auth.create(user.getSocialInfo(), authToken.refreshToken(), deviceId));
8585

8686
return authToken;
8787
}

src/main/java/com/projectlyrics/server/domain/common/message/ErrorCode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public enum ErrorCode {
3232
INVALID_TOKEN_PREFIX(HttpStatus.BAD_REQUEST, "01009", "Bearer 인증 형식이 아닙니다."),
3333
INVALID_SOCIAL_TOKEN(HttpStatus.UNAUTHORIZED, "01010", "유효하지 않은 소셜 인증 토큰입니다."),
3434
AUTH_NOT_FOUND(HttpStatus.NOT_FOUND, "01011", "해당 인증 정보를 찾을 수 없습니다."),
35+
NOT_REGISTERED_DEVICE(HttpStatus.NOT_FOUND, "01012", "타 기기에서 로그인했거나 등록되지 않은 기기입니다."),
3536

3637
// User
3738
USER_NOT_FOUND(HttpStatus.NOT_FOUND, "02000", "해당 유저가 존재하지 않습니다."),

src/main/java/com/projectlyrics/server/domain/song/repository/impl/JdbcSongCommandRepository.java

Lines changed: 33 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,42 @@
77
import org.springframework.stereotype.Repository;
88

99
import java.util.List;
10+
import java.util.Objects;
1011

1112
@RequiredArgsConstructor
1213
@Repository
1314
public class JdbcSongCommandRepository implements SongCommandRepository {
1415

1516
private final JdbcTemplate jdbcTemplate;
16-
private final String insertQuery = "INSERT INTO songs (id, artist_id, spotify_id, name, release_date, album_name, image_url) VALUES (?, ?, ?, ?, ?, ?, ?)";
17+
private final String insertQuery = "INSERT INTO songs (artist_id, spotify_id, name, release_date, album_name, image_url) VALUES (?, ?, ?, ?, ?, ?)";
18+
private final String insertQueryWithId = "INSERT INTO songs (id, artist_id, spotify_id, name, release_date, album_name, image_url) VALUES (?, ?, ?, ?, ?, ?, ?)";
1719

1820
@Override
1921
public Song save(Song song) {
20-
jdbcTemplate.update(
21-
insertQuery,
22-
song.getId(),
23-
song.getArtist().getId(),
24-
song.getSpotifyId(),
25-
song.getName(),
26-
song.getReleaseDate(),
27-
song.getAlbumName(),
28-
song.getImageUrl()
29-
);
22+
if (Objects.nonNull(song.getId())) {
23+
jdbcTemplate.update(
24+
insertQueryWithId,
25+
song.getId(),
26+
song.getArtist().getId(),
27+
song.getSpotifyId(),
28+
song.getName(),
29+
song.getReleaseDate(),
30+
song.getAlbumName(),
31+
song.getImageUrl()
32+
);
33+
}
34+
35+
else {
36+
jdbcTemplate.update(
37+
insertQuery,
38+
song.getArtist().getId(),
39+
song.getSpotifyId(),
40+
song.getName(),
41+
song.getReleaseDate(),
42+
song.getAlbumName(),
43+
song.getImageUrl()
44+
);
45+
}
3046

3147
return song;
3248
}
@@ -38,13 +54,12 @@ public void saveAll(List<Song> songs) {
3854
songs,
3955
songs.size(),
4056
(ps, song) -> {
41-
ps.setLong(1, song.getId());
42-
ps.setLong(2, song.getArtist().getId());
43-
ps.setString(3, song.getSpotifyId());
44-
ps.setString(4, song.getName());
45-
ps.setDate(5, java.sql.Date.valueOf(song.getReleaseDate()));
46-
ps.setString(6, song.getAlbumName());
47-
ps.setString(7, song.getImageUrl());
57+
ps.setLong(1, song.getArtist().getId());
58+
ps.setString(2, song.getSpotifyId());
59+
ps.setString(3, song.getName());
60+
ps.setDate(4, java.sql.Date.valueOf(song.getReleaseDate()));
61+
ps.setString(5, song.getAlbumName());
62+
ps.setString(6, song.getImageUrl());
4863
}
4964
);
5065
}

src/main/java/com/projectlyrics/server/global/configuration/WebConfig.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@
22

33
import com.projectlyrics.server.domain.auth.authentication.AuthArgumentResolver;
44
import com.projectlyrics.server.domain.auth.authentication.interceptor.AuthInterceptor;
5+
import com.projectlyrics.server.domain.auth.authentication.interceptor.DeviceIdInterceptor;
56
import com.projectlyrics.server.domain.auth.authentication.interceptor.SlackInterceptor;
67
import com.projectlyrics.server.domain.auth.authentication.interceptor.AdminInterceptor;
78
import com.projectlyrics.server.global.converter.ProfileCharacterConverter;
89
import lombok.RequiredArgsConstructor;
10+
import org.springframework.beans.factory.annotation.Autowired;
911
import org.springframework.context.annotation.Configuration;
1012
import org.springframework.format.FormatterRegistry;
1113
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
1214
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
1315
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
1416

1517
import java.util.List;
18+
import java.util.Objects;
1619

1720
@Configuration
1821
@RequiredArgsConstructor
@@ -23,6 +26,9 @@ public class WebConfig implements WebMvcConfigurer {
2326
private final AdminInterceptor adminInterceptor;
2427
private final SlackInterceptor slackInterceptor;
2528

29+
@Autowired(required = false)
30+
private DeviceIdInterceptor deviceIdInterceptor;
31+
2632
@Override
2733
public void addInterceptors(InterceptorRegistry registry) {
2834
registry.addInterceptor(authInterceptor)
@@ -33,6 +39,13 @@ public void addInterceptors(InterceptorRegistry registry) {
3339
.excludePathPatterns("/api/v1/auth/token")
3440
.excludePathPatterns("/api/v1/slack/interactive");
3541

42+
if (Objects.nonNull(deviceIdInterceptor)) {
43+
registry.addInterceptor(deviceIdInterceptor)
44+
.addPathPatterns("/api/**")
45+
.excludePathPatterns("/api/v1/auth/sign-in")
46+
.addPathPatterns("/api/v1/auth/sign-up");
47+
}
48+
3649
registry.addInterceptor(adminInterceptor)
3750
.addPathPatterns("/api/v1/artists/**")
3851
.addPathPatterns("/api/v1/notifications/public")

0 commit comments

Comments
 (0)