[회원 정보 개선] refresh_token 필드 길이 증가 및 MemberMapper에 DTO 업데이트 메서드 추가. MemberService에서 사용자 조회 및 업데이트 로직 개선, JWT 필터에서 refresh_token 저장 로직 제거.
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
name varchar(100) not null,
|
||||
password varchar(100) not null,
|
||||
user_id varchar(100) not null,
|
||||
refresh_token varchar(200),
|
||||
refresh_token varchar(1024),
|
||||
email varchar(255) not null,
|
||||
primary key (oid)
|
||||
);
|
||||
|
@@ -44,7 +44,7 @@ public class Member extends BaseEntity {
|
||||
@Builder.Default
|
||||
private Boolean useFlag = true;
|
||||
|
||||
@Column(name = "refresh_token", length = 200)
|
||||
@Column(name = "refresh_token", length = 1024)
|
||||
private String refreshToken;
|
||||
|
||||
@Column(name = "last_login_at")
|
||||
|
@@ -46,4 +46,14 @@ public interface MemberMapper {
|
||||
* MemberDto를 CreateMemberResponseDto로 변환
|
||||
*/
|
||||
CreateMemberResponseDto toCreateMemberResponseDto(MemberDto memberDto);
|
||||
|
||||
/**
|
||||
* MemberDto의 값으로 기존 Member 엔티티 업데이트 (null이 아닌 필드만)
|
||||
*/
|
||||
@Mapping(target = "oid", ignore = true)
|
||||
@Mapping(target = "createdAt", ignore = true)
|
||||
@Mapping(target = "updatedAt", ignore = true)
|
||||
@Mapping(target = "createdOid", ignore = true)
|
||||
@Mapping(target = "updatedOid", ignore = true)
|
||||
void updateMemberFromDto(MemberDto memberDto, @org.mapstruct.MappingTarget Member member);
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.bio.bio_backend.domain.base.member.entity.Member;
|
||||
import java.util.Optional;
|
||||
import java.util.List;
|
||||
|
||||
@Repository
|
||||
public interface MemberRepository extends JpaRepository<Member, Long> {
|
||||
@@ -12,6 +13,21 @@ public interface MemberRepository extends JpaRepository<Member, Long> {
|
||||
// 사용자 ID로 회원 조회 (Optional 반환)
|
||||
Optional<Member> findByUserId(String userId);
|
||||
|
||||
// 사용자 ID로 첫 번째 회원 조회 (userId가 unique하지 않을 경우 대비)
|
||||
Optional<Member> findFirstByUserId(String userId);
|
||||
|
||||
// 사용자 ID로 활성화된 회원 조회
|
||||
Optional<Member> findByUserIdAndUseFlagTrue(String userId);
|
||||
|
||||
// 사용자 ID로 활성화된 회원 첫 번째 조회
|
||||
Optional<Member> findFirstByUserIdAndUseFlagTrue(String userId);
|
||||
|
||||
// 사용자 ID 존재 여부 확인 (활성화된 회원만)
|
||||
boolean existsByUserIdAndUseFlagTrue(String userId);
|
||||
|
||||
// 사용자 ID 존재 여부 확인
|
||||
boolean existsByUserId(String userId);
|
||||
|
||||
// 활성화된 회원 목록 조회
|
||||
List<Member> findByUseFlagTrue();
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
package com.bio.bio_backend.domain.base.member.service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -14,8 +15,6 @@ public interface MemberService extends UserDetailsService {
|
||||
|
||||
MemberDto createMember(MemberDto memberDTO);
|
||||
|
||||
void updateRefreshToken(MemberDto memberDTO);
|
||||
|
||||
String getRefreshToken(String id);
|
||||
|
||||
int deleteRefreshToken(String id);
|
||||
|
@@ -32,7 +32,7 @@ public class MemberServiceImpl implements MemberService {
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException {
|
||||
Member member = memberRepository.findByUserId(id)
|
||||
Member member = memberRepository.findByUserIdAndUseFlagTrue(id)
|
||||
.orElseThrow(() -> new UsernameNotFoundException("사용자를 찾을 수 없습니다: " + id));
|
||||
|
||||
// MapStruct를 사용하여 Member 엔티티를 MemberDto로 변환
|
||||
@@ -45,7 +45,7 @@ public class MemberServiceImpl implements MemberService {
|
||||
@Transactional
|
||||
public MemberDto createMember(MemberDto memberDto) {
|
||||
// userId 중복 체크
|
||||
if (memberRepository.existsByUserId(memberDto.getUserId())) {
|
||||
if (memberRepository.existsByUserIdAndUseFlagTrue(memberDto.getUserId())) {
|
||||
throw new ApiException(ApiResponseCode.USER_ID_DUPLICATE);
|
||||
}
|
||||
|
||||
@@ -68,19 +68,24 @@ public class MemberServiceImpl implements MemberService {
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateRefreshToken(MemberDto memberDTO) {
|
||||
// JPA를 사용하여 refresh token 업데이트
|
||||
Member member = memberRepository.findByUserId(memberDTO.getUserId())
|
||||
.orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + memberDTO.getUserId()));
|
||||
public int updateMember(MemberDto memberDto) {
|
||||
Member member = memberRepository.findFirstByUserIdAndUseFlagTrue(memberDto.getUserId())
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
|
||||
|
||||
memberMapper.updateMemberFromDto(memberDto, member);
|
||||
|
||||
if (memberDto.getPassword() != null && !memberDto.getPassword().isEmpty()) {
|
||||
member.setPassword(bCryptPasswordEncoder.encode(memberDto.getPassword()));
|
||||
}
|
||||
|
||||
member.setRefreshToken(memberDTO.getRefreshToken());
|
||||
memberRepository.save(member);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRefreshToken(String id) {
|
||||
Member member = memberRepository.findByUserId(id)
|
||||
.orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + id));
|
||||
Member member = memberRepository.findFirstByUserIdAndUseFlagTrue(id)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
|
||||
|
||||
return member.getRefreshToken();
|
||||
}
|
||||
@@ -88,8 +93,8 @@ public class MemberServiceImpl implements MemberService {
|
||||
@Override
|
||||
@Transactional
|
||||
public int deleteRefreshToken(String id) {
|
||||
Member member = memberRepository.findByUserId(id)
|
||||
.orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + id));
|
||||
Member member = memberRepository.findFirstByUserIdAndUseFlagTrue(id)
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
|
||||
|
||||
member.setRefreshToken(null);
|
||||
memberRepository.save(member);
|
||||
@@ -98,10 +103,8 @@ public class MemberServiceImpl implements MemberService {
|
||||
|
||||
@Override
|
||||
public List<MemberDto> selectMemberList(Map<String, String> params) {
|
||||
// JPA를 사용하여 회원 목록 조회 (간단한 구현)
|
||||
List<Member> members = memberRepository.findAll();
|
||||
List<Member> members = memberRepository.findByUseFlagTrue();
|
||||
|
||||
// MapStruct를 사용하여 Member 엔티티 리스트를 MemberDto 리스트로 변환
|
||||
return memberMapper.toMemberDtoList(members);
|
||||
}
|
||||
|
||||
@@ -115,29 +118,13 @@ public class MemberServiceImpl implements MemberService {
|
||||
return memberMapper.toMemberDto(member);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int updateMember(MemberDto memberDto) {
|
||||
Member member = memberRepository.findByUserId(memberDto.getUserId())
|
||||
.orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + memberDto.getUserId()));
|
||||
|
||||
// 비밀번호가 변경된 경우 암호화
|
||||
if (memberDto.getPassword() != null && !memberDto.getPassword().isEmpty()) {
|
||||
member.setPassword(bCryptPasswordEncoder.encode(memberDto.getPassword()));
|
||||
}
|
||||
|
||||
member.setRole(memberDto.getRole());
|
||||
member.setUseFlag(memberDto.getUseFlag());
|
||||
|
||||
memberRepository.save(member);
|
||||
return 1; // 성공 시 1 반환
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public int deleteMember(MemberDto memberDto) {
|
||||
Member member = memberRepository.findByUserId(memberDto.getUserId())
|
||||
.orElseThrow(() -> new RuntimeException("회원을 찾을 수 없습니다. id: " + memberDto.getUserId()));
|
||||
Member member = memberRepository.findFirstByUserId(memberDto.getUserId())
|
||||
.orElseThrow(() -> new ApiException(ApiResponseCode.USER_NOT_FOUND));
|
||||
|
||||
member.setUseFlag(false);
|
||||
|
||||
|
@@ -9,14 +9,15 @@ import com.bio.bio_backend.global.dto.ApiResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.LoginRequestDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.LoginResponseDto;
|
||||
import com.bio.bio_backend.domain.base.member.dto.MemberDto;
|
||||
import com.bio.bio_backend.domain.base.member.service.MemberService;
|
||||
import com.bio.bio_backend.global.constants.ApiResponseCode;
|
||||
import com.bio.bio_backend.global.utils.JwtUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
@@ -36,15 +37,20 @@ public class JwtTokenIssuanceFilter extends UsernamePasswordAuthenticationFilter
|
||||
private final AuthenticationManager authenticationManager;
|
||||
private final JwtUtils jwtUtils;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final MemberService memberService;
|
||||
|
||||
// 사용자 login 인증 처리
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
|
||||
LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);
|
||||
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(requestDto.getUserId(), requestDto.getPassword());
|
||||
try {
|
||||
LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);
|
||||
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
|
||||
requestDto.getUserId(), requestDto.getPassword());
|
||||
|
||||
return authenticationManager.authenticate(authToken);
|
||||
return authenticationManager.authenticate(authToken);
|
||||
} catch (IOException e) {
|
||||
throw new AuthenticationServiceException("로그인 요청 파싱 중 오류가 발생했습니다", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 사용자 인증 성공 후 token 발급
|
||||
@@ -59,11 +65,9 @@ public class JwtTokenIssuanceFilter extends UsernamePasswordAuthenticationFilter
|
||||
String accessToken = jwtUtils.createAccessToken(member.getUserId(), member.getRole().getValue());
|
||||
String refreshToken = jwtUtils.createRefreshToken(member.getUserId(), member.getRole().getValue());
|
||||
|
||||
// Refresh 토큰을 DB에 저장
|
||||
jwtUtils.saveRefreshToken(member.getUserId(), refreshToken);
|
||||
|
||||
member.setRefreshToken(refreshToken);
|
||||
member.setLastLoginAt(LocalDateTime.now());
|
||||
memberService.updateMember(member);
|
||||
|
||||
// Refresh 토큰 쿠키 저장
|
||||
jwtUtils.setRefreshTokenCookie(response, refreshToken);
|
||||
|
@@ -37,7 +37,7 @@ public class WebSecurity {
|
||||
private final SecurityPathConfig securityPathConfig;
|
||||
|
||||
private JwtTokenIssuanceFilter getJwtTokenIssuanceFilter(AuthenticationManager authenticationManager) throws Exception {
|
||||
JwtTokenIssuanceFilter filter = new JwtTokenIssuanceFilter(authenticationManager, jwtUtils, objectMapper);
|
||||
JwtTokenIssuanceFilter filter = new JwtTokenIssuanceFilter(authenticationManager, jwtUtils, objectMapper, memberService);
|
||||
filter.setFilterProcessesUrl("/login");
|
||||
filter.setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler(objectMapper));
|
||||
return filter;
|
||||
|
@@ -105,25 +105,10 @@ public class JwtUtils {
|
||||
Long.parseLong(Objects.requireNonNull(env.getProperty("token.expiration_time_refresh"))));
|
||||
}
|
||||
|
||||
// Refresh Token을 DB에 저장
|
||||
public void saveRefreshToken(String username, String refreshToken) {
|
||||
MemberDto member = new MemberDto();
|
||||
member.setUserId(username);
|
||||
member.setRefreshToken(refreshToken);
|
||||
memberService.updateRefreshToken(member);
|
||||
}
|
||||
|
||||
// Refresh Token 생성 및 DB 저장 (기존 호환성을 위한 메서드)
|
||||
public String createAndSaveRefreshToken(String username, String role) {
|
||||
String refreshToken = createRefreshToken(username, role);
|
||||
saveRefreshToken(username, refreshToken);
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
// Refresh Token 갱신 (Access Token 갱신 시 함께)
|
||||
public String refreshTokens(String username, String role) {
|
||||
// 새로운 Refresh Token 생성 및 DB 저장
|
||||
String newRefreshToken = createAndSaveRefreshToken(username, role);
|
||||
String newRefreshToken = createRefreshToken(username, role);
|
||||
|
||||
log.info("Refresh Token 갱신 완료: {}", username);
|
||||
return newRefreshToken;
|
||||
|
Reference in New Issue
Block a user