1. Member Entity
public class Member extends BaseEntity{
@Id
@Column(nullable = false, unique = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true)
private String uid; // 아이디
@Column(nullable = false, length = 1000)
private String pw; // 비밀번호
private String name; // 이름
@Column(nullable = false, unique = true)
private String email; // 이메일
private String birth; // 생년월일
@Column(unique = true)
private String phone; // 전화번호
private boolean del; // 회원탈퇴
@Enumerated(EnumType.STRING)
private MemberRole memberRole;
@Builder
public Member(Long id, String email, String pw, String uid, String name, String birth, String phone, MemberRole memberRole) {
this.id = id;
this.email = email;
this.pw = pw;
this.uid = uid;
this.name = name;
this.birth = birth;
this.phone = phone;
this.memberRole = memberRole;
}
}
public enum MemberRole {
USER("USER"),
ADMIN("ADMIN");
private final String value;
}
MemberRole은 enum 클래스로 따로 만들어줬다.
2. MemberRepositoy
public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findByUid(String uid);
boolean existsByUid(String uid); // 중복 가입 방지
}
uid를 사용해서 로그인 할 것이기 때문에, findByUid 메서드를 만들었다.
3. MemberService
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class MemberService {
private final MemberRepository memberRepository;
public MemberResponseDto findMemberInfoById(Long memberId) {
return memberRepository.findById(memberId)
.map(MemberResponseDto::of)
.orElseThrow(() -> new RuntimeException("로그인 유저 정보가 없습니다."));
}
public MemberResponseDto findMemberInfoByUid(String uid) {
return memberRepository.findByUid(uid)
.map(MemberResponseDto::of)
.orElseThrow(() -> new RuntimeException("유저 정보가 없습니다."));
}
}
member의 id와 uid 로 회원 정보를 가져오는 service
4. MemberController
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/member")
public class MemberController {
private final MemberService memberService;
@GetMapping("/me")
public ResponseEntity<MemberResponseDto> findMemberInfoById(){
return ResponseEntity.ok(memberService.findMemberInfoById(SecurityUtil.getCurrentMemberId()));
}
@GetMapping("/{uid}")
public ResponseEntity<MemberResponseDto> findMemberInfoByUid(@PathVariable String uid){
return ResponseEntity.ok(memberService.findMemberInfoByUid(uid));
}
}
API 요청이 들어오면 필터에서 Access Token 을 복호화 해서 유저 정보를 꺼내 SecurityContext 라는 곳에 저장한다.
SecurityContext 에 저장된 유저 정보는 전역으로 어디서든 꺼낼 수 있다.
4. SecurityUtil
@Log4j2
public class SecurityUtil {
private SecurityUtil() {}
// SecurityContext 에 유저 정보가 저장되는 시점
// Request 가 들어올 때 JwtFilter 의 doFilter 에서 저장
public static Long getCurrentMemberId(){
// 현재 memberId를 조회하는 코드
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null || authentication.getName() == null){
throw new RuntimeException("Security Context 에 인증 정보가 없습니다.");
}
return Long.parseLong(authentication.getName());
}
}
API 호출 시, Member의 정보가 헤더에 담겨져 올텐데, 어떤 Member가 API를 요청했는지 조회하는 코드이다.
Principal 멤버 변수인 username에 id가 들어있다.
만약 인증 정보가 없어서 authentication 객체가 null이라면 에러가 뜨고,
인증 정보가 있다면 authentication.getName()으로 id를 반환해준다.
더보기
Authentication = 인증 된 사용자에 대한 상세 정보, 즉 통행증 역할. SecurityContextHolder 내부의 SecurityContext에 저장됨.
SecurityContextHolder = Spring Security 인증 모델의 핵심으로 SecurityContext가 포함됨. 인증된 사용자의 세부 정보를 저장하는 곳으로 어떤 값이든지 값을 포함하고 있다면 현재 인증 된 사용자로 사용됨.
'springboot 개인프로젝트 기록' 카테고리의 다른 글
07. Spring Security + JWT를 이용한 로그인, 회원가입 구현 (4) (1) | 2024.03.31 |
---|---|
06. Spring Security + JWT를 이용한 로그인, 회원가입 구현 (3) (0) | 2024.03.30 |
04. Spring Security + JWT를 이용한 로그인 구현 (1) (0) | 2024.03.28 |
03. 부트스트랩 템플릿 적용 (0) | 2024.03.26 |
02. 1차 ERD 구성 및 구현할 기능들 (0) | 2024.03.22 |