Skip to content

Commit 3b362d9

Browse files
authored
Merge branch 'main' into feature/111-add-cors-setting
2 parents 0cc8c03 + 0b50ac0 commit 3b362d9

32 files changed

+816
-58
lines changed

src/main/java/com/somemore/auth/jwt/filter/JwtAuthenticationToken.java renamed to src/main/java/com/somemore/auth/authentication/JwtAuthenticationToken.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
package com.somemore.auth.jwt.filter;
1+
package com.somemore.auth.authentication;
22

3+
import lombok.EqualsAndHashCode;
34
import org.springframework.security.authentication.AbstractAuthenticationToken;
45
import org.springframework.security.core.GrantedAuthority;
56

67
import java.io.Serializable;
78
import java.util.Collection;
89

10+
@EqualsAndHashCode(callSuper = true)
911
public class JwtAuthenticationToken extends AbstractAuthenticationToken {
1012
private final Serializable principal;
1113
private final transient Object credentials;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.somemore.auth.idpw.filter;
2+
3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.somemore.auth.cookie.CookieUseCase;
5+
import com.somemore.auth.jwt.domain.EncodedToken;
6+
import com.somemore.auth.jwt.domain.UserRole;
7+
import com.somemore.auth.jwt.usecase.GenerateTokensOnLoginUseCase;
8+
import jakarta.servlet.FilterChain;
9+
import jakarta.servlet.http.HttpServletRequest;
10+
import jakarta.servlet.http.HttpServletResponse;
11+
import lombok.RequiredArgsConstructor;
12+
import lombok.extern.slf4j.Slf4j;
13+
import org.springframework.http.HttpStatus;
14+
import org.springframework.http.MediaType;
15+
import org.springframework.http.ProblemDetail;
16+
import org.springframework.security.authentication.AuthenticationManager;
17+
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
18+
import org.springframework.security.core.Authentication;
19+
import org.springframework.security.core.AuthenticationException;
20+
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
21+
22+
import java.io.IOException;
23+
import java.util.UUID;
24+
25+
@RequiredArgsConstructor
26+
@Slf4j
27+
public class IdPwAuthFilter extends UsernamePasswordAuthenticationFilter {
28+
29+
private final AuthenticationManager authenticationManager;
30+
private final GenerateTokensOnLoginUseCase generateTokensOnLoginUseCase;
31+
private final CookieUseCase cookieUseCase;
32+
private final ObjectMapper objectMapper;
33+
34+
@Override
35+
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
36+
String accountId = request.getParameter("account_id");
37+
String accountPassword = request.getParameter("account_password");
38+
39+
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(accountId, accountPassword);
40+
return authenticationManager.authenticate(authToken);
41+
}
42+
43+
@Override
44+
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
45+
response.setStatus(HttpServletResponse.SC_OK);
46+
EncodedToken accessToken = generateTokensOnLoginUseCase.saveRefreshTokenAndReturnAccessToken(UUID.fromString(authResult.getName()), UserRole.CENTER);
47+
cookieUseCase.setAccessToken(response, accessToken.value());
48+
}
49+
50+
@Override
51+
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException {
52+
ProblemDetail problemDetail = buildUnauthorizedProblemDetail(failed);
53+
configureUnauthorizedResponse(response);
54+
55+
objectMapper.writeValue(response.getWriter(), problemDetail);
56+
}
57+
58+
private void configureUnauthorizedResponse(HttpServletResponse response) {
59+
response.setStatus(HttpStatus.UNAUTHORIZED.value());
60+
response.setContentType(MediaType.APPLICATION_PROBLEM_JSON_VALUE);
61+
response.setCharacterEncoding("UTF-8");
62+
}
63+
64+
private ProblemDetail buildUnauthorizedProblemDetail(AuthenticationException e) {
65+
log.error("IdPwAuthFilter 예외 발생: {}", e.getMessage());
66+
67+
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNAUTHORIZED, "인증에서 오류가 발생했습니다.");
68+
problemDetail.setTitle("인증 에러");
69+
problemDetail.setProperty("timestamp", System.currentTimeMillis());
70+
return problemDetail;
71+
}
72+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package com.somemore.auth.idpw.provider;
2+
3+
import com.somemore.auth.authentication.JwtAuthenticationToken;
4+
import com.somemore.auth.jwt.domain.EncodedToken;
5+
import com.somemore.auth.jwt.domain.TokenType;
6+
import com.somemore.auth.jwt.domain.UserRole;
7+
import com.somemore.auth.jwt.usecase.JwtUseCase;
8+
import com.somemore.center.usecase.query.CenterSignUseCase;
9+
import lombok.RequiredArgsConstructor;
10+
import org.springframework.security.authentication.AuthenticationProvider;
11+
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
12+
import org.springframework.security.core.Authentication;
13+
import org.springframework.security.core.AuthenticationException;
14+
import org.springframework.security.core.authority.SimpleGrantedAuthority;
15+
import org.springframework.security.crypto.password.PasswordEncoder;
16+
import org.springframework.stereotype.Component;
17+
import org.springframework.transaction.annotation.Transactional;
18+
19+
import java.util.List;
20+
21+
@Component
22+
@RequiredArgsConstructor
23+
@Transactional(readOnly = true)
24+
public class CustomAuthenticationProvider implements AuthenticationProvider {
25+
26+
private final CenterSignUseCase centerSignUseCase;
27+
private final JwtUseCase jwtUseCase;
28+
private final PasswordEncoder passwordEncoder;
29+
30+
@Override
31+
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
32+
String accountId = authentication.getName();
33+
String rawAccountPassword = authentication.getCredentials().toString();
34+
35+
String centerId = centerSignUseCase.getIdByAccountId(accountId).toString();
36+
String encodedPassword = centerSignUseCase.getPasswordByAccountId(accountId);
37+
38+
if (passwordEncoder.matches(rawAccountPassword, encodedPassword)) {
39+
EncodedToken accessToken = jwtUseCase.generateToken(
40+
centerId,
41+
UserRole.CENTER.getAuthority(),
42+
TokenType.ACCESS
43+
);
44+
45+
return new JwtAuthenticationToken(
46+
centerId,
47+
accessToken,
48+
List.of(new SimpleGrantedAuthority(UserRole.CENTER.getAuthority()))
49+
);
50+
}
51+
52+
return null;
53+
}
54+
55+
@Override
56+
public boolean supports(Class<?> authentication) {
57+
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
58+
}
59+
}

src/main/java/com/somemore/auth/jwt/filter/JwtAuthFilter.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.somemore.auth.jwt.filter;
22

3+
import com.somemore.auth.authentication.JwtAuthenticationToken;
34
import com.somemore.auth.jwt.domain.EncodedToken;
45
import com.somemore.auth.jwt.exception.JwtErrorType;
56
import com.somemore.auth.jwt.exception.JwtException;
@@ -30,12 +31,18 @@ public class JwtAuthFilter extends OncePerRequestFilter {
3031
@Override
3132
protected boolean shouldNotFilter(HttpServletRequest request) {
3233
String token = request.getHeader("Authorization");
33-
return token == null || token.isEmpty();
34+
String path = request.getRequestURI();
35+
36+
return token == null
37+
|| token.isEmpty()
38+
|| path.equals("/api/center/sign-in");
3439
}
3540

3641
@Override
37-
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
42+
protected void doFilterInternal(HttpServletRequest request,
43+
HttpServletResponse response,
3844
FilterChain filterChain) throws ServletException, IOException {
45+
3946
EncodedToken accessToken = getAccessToken(request);
4047
jwtUseCase.processAccessToken(accessToken, response);
4148

src/main/java/com/somemore/auth/jwt/filter/JwtExceptionFilter.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ public class JwtExceptionFilter extends OncePerRequestFilter {
2424
private final ObjectMapper objectMapper;
2525

2626
@Override
27-
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
27+
protected void doFilterInternal(HttpServletRequest request,
28+
HttpServletResponse response,
29+
FilterChain filterChain) throws ServletException, IOException {
2830
try {
2931
filterChain.doFilter(request, response);
3032
} catch (JwtException e) {
@@ -42,8 +44,10 @@ private void configureUnauthorizedResponse(HttpServletResponse response) {
4244
}
4345

4446
private ProblemDetail buildUnauthorizedProblemDetail(JwtException e) {
45-
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNAUTHORIZED, e.getMessage());
46-
problemDetail.setTitle("Authentication Error");
47+
log.error("JwtFilter 예외 발생: {}", e.getMessage());
48+
49+
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.UNAUTHORIZED, "인증에서 오류가 발생했습니다.");
50+
problemDetail.setTitle("인증 에러");
4751
problemDetail.setProperty("timestamp", System.currentTimeMillis());
4852
return problemDetail;
4953
}

src/main/java/com/somemore/auth/jwt/service/GenerateTokensOnLoginService.java

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,27 @@ public class GenerateTokensOnLoginService implements GenerateTokensOnLoginUseCas
2424
private final RefreshTokenManager refreshTokenManager;
2525

2626
@Override
27-
public EncodedToken saveRefreshTokenAndReturnAccessToken(UUID volunteerId) {
28-
EncodedToken accessToken = generateToken(volunteerId, TokenType.ACCESS);
29-
RefreshToken refreshToken = generateRefreshToken(volunteerId, accessToken);
27+
public EncodedToken saveRefreshTokenAndReturnAccessToken(UUID userId, UserRole role) {
28+
EncodedToken accessToken = jwtGenerator.generateToken(
29+
userId.toString(),
30+
role.getAuthority(),
31+
TokenType.ACCESS
32+
);
33+
RefreshToken refreshToken = generateRefreshToken(userId, role, accessToken);
3034
saveRefreshToken(refreshToken);
3135

3236
return accessToken;
3337
}
3438

35-
private EncodedToken generateToken(UUID volunteerId, TokenType tokenType) {
36-
return jwtGenerator.generateToken(
37-
volunteerId.toString(),
38-
UserRole.VOLUNTEER.getAuthority(),
39-
tokenType);
40-
}
41-
42-
private RefreshToken generateRefreshToken(UUID volunteerId, EncodedToken accessToken) {
39+
private RefreshToken generateRefreshToken(UUID userId, UserRole role, EncodedToken accessToken) {
4340
return new RefreshToken(
44-
volunteerId.toString(),
41+
userId.toString(),
4542
accessToken,
46-
generateToken(
47-
volunteerId,
48-
TokenType.REFRESH));
43+
jwtGenerator.generateToken(
44+
userId.toString(),
45+
role.getAuthority(),
46+
TokenType.REFRESH)
47+
);
4948
}
5049

5150
private void saveRefreshToken(RefreshToken refreshToken) {
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package com.somemore.auth.jwt.usecase;
22

33
import com.somemore.auth.jwt.domain.EncodedToken;
4+
import com.somemore.auth.jwt.domain.UserRole;
45

56
import java.util.UUID;
67

78
public interface GenerateTokensOnLoginUseCase {
8-
EncodedToken saveRefreshTokenAndReturnAccessToken(UUID volunteerId);
9+
EncodedToken saveRefreshTokenAndReturnAccessToken(UUID userId, UserRole role);
910
}

src/main/java/com/somemore/auth/oauth/handler/success/CustomOAuthSuccessHandler.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.somemore.auth.cookie.CookieUseCase;
44
import com.somemore.auth.jwt.domain.EncodedToken;
5+
import com.somemore.auth.jwt.domain.UserRole;
56
import com.somemore.auth.jwt.usecase.GenerateTokensOnLoginUseCase;
67
import com.somemore.auth.oauth.OAuthProvider;
78
import com.somemore.auth.oauth.naver.service.query.ProcessNaverOAuthUserService;
@@ -46,7 +47,10 @@ public void onAuthenticationSuccess(HttpServletRequest request, HttpServletRespo
4647
}
4748

4849
UUID volunteerId = volunteerQueryUseCase.getVolunteerIdByOAuthId(oAuthId);
49-
EncodedToken accessToken = generateTokensOnLoginUseCase.saveRefreshTokenAndReturnAccessToken(volunteerId);
50+
EncodedToken accessToken =
51+
generateTokensOnLoginUseCase.saveRefreshTokenAndReturnAccessToken(
52+
volunteerId, UserRole.VOLUNTEER
53+
);
5054

5155
cookieUseCase.setAccessToken(response, accessToken.value());
5256
redirectUseCase.redirect(request, response, frontendRootUrl);

src/main/java/com/somemore/center/repository/CenterJpaRepository.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,5 @@ public interface CenterJpaRepository extends JpaRepository<Center, Long> {
1010
boolean existsById(UUID id);
1111
Optional<Center> findCenterById(UUID id);
1212
Optional<Center> findByName(String name);
13+
boolean existsByIdAndDeletedIsFalse(UUID id);
1314
}

src/main/java/com/somemore/center/repository/CenterRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,8 @@ default boolean doesNotExistById(UUID id) {
1717
}
1818
Optional<Center> findCenterById(UUID id);
1919
List<CenterOverviewInfo> findCenterOverviewsByIds(List<UUID> ids);
20+
UUID findIdByAccountId(String accountId);
21+
String findPasswordByAccountId(String accountId);
2022
void deleteAllInBatch();
23+
2124
}

0 commit comments

Comments
 (0)