나 정말 뭘 해야 되지...?
모르겠다.
그래도 일단 공부하려고 컴퓨터를 키면
그때부터 유튜브와의 전쟁이 시작된다.
영상 하나 보고
관련 영상 하나 더 보고
그렇게 계속 보고…
정작 머릿속에는 아무것도 남지 않는다.
그 상태로 하루가 끝난다.
돌이켜보니 의지의 문제가 아닌것 같다
무엇을 해야 하는지가 너무 추상적이었다.
AOP 리팩토링 하기 CORS 개념 적용하기 등등
목표를 읽으면 바로 무언가를 해야될지 떠오르지 않는다.
시작 지점이 보이지 않기 때문에 어렵다.
마감이니까 임박해서 허겁지겁 WIL을 쓰고
코드를 추가하는 이유도 사실은 쉬운데
하기 싫고 어렵다고 생각해서 그렇다.
그러니까 앞으로 할 일들은
구체적으로, 쉽게 만들기 !
프론트 API 요청을 보냈는데 이상한 상황을 겪었다.
크롬 브라우저 콘솔에는 빨간색 에러 메시지가 찍혀있다.
CORS!!
처음엔 프론트 엔드가 요청을 잘못 보낸줄 알았다.
하지만 문제는 브라우저 문제였고
백엔드에서 처리 가능한 문제였다
CORS는 흔히 보안 정책처럼 설명된다
정확하게는 브라우저가 요청을 처리하는 규칙 이다
핵심을 정리하면 이렇다.
이걸 이해하지 못하면 계속 서버 코드만 뒤진다.
CORS는 브라우저에만 적용되는 규칙이다.
Postman은 브라우저가 아니기 때문에
CORS 검사를 하지 않는다.
브라우저는 어떤 요청을 보내기 전에 먼저 묻는다.
“이 요청 보내도 괜찮아?”
이게 Preflight 요청이다.
흐름을 순서대로 정리하면:
중요한 점은 이것이다.
서버는 차단하지 않는다.
판단자는 항상 브라우저다.
서버는 이런 요청은 허용해 라고 알려줄 뿐...
로그인 체크는 간단하게 보였다.
세션 하나만 꺼내서 값만 확인하면 끝이다.
문제는 USER / ADMIN 으로 갈라지면서 시작됐다
RequestContextHolder.currentRequestAttributes()
간단하게 RequestContextHolder는
HTTP 요청을 처리 중이라는 전제 하에 요청 내용을 가져온다.
아니면 그냥 NPE 던짐 → 나 : ??? 넌 어디서 왔니
getLoginMemberId()
getLoginAdminId()
AOP가 세션 내부 구조를 알고 있다는 건 설계적으로 좋지 않다.
역할이 늘면? → 역할에 맞춰서 추가해되야됨
API 타입이 늘면?
AOP가 계속 수정된다.
초기 구현에서는 다음과 같이 분기하고 있었다.
switch (loginCheck.type().toString())
당시에는 이 코드가 문제라고 생각하지 않았다.
USER, ADMIN 두 값만 비교하면 되니 충분해 보였다.
이 부분이 문제라는 걸 인지하게 된 건,
enum 타입에 대한 설명을 들은 이후였다.
@LoginCheck의 type은 단순한 문자열이 아니라
의미를 가진 타입이라는 점을 그때 처음 제대로 이해했다.
enum을 사용한다는 건,
하지만 이를 String으로 변환해 비교하는 순간,
이런 장점들은 전부 사라진다.
즉, 이 코드는 동작은 하지만
타입이 제공하던 보호를 스스로 포기한 상태였다.
이 점을 이해한 뒤에는,
분기 기준을 굳이 문자열로 바꿀 이유가 없다는 게 분명해졌다.
그래서 이후 코드에서는 enum 자체를 기준으로 분기하도록 수정했다.
switch (loginCheck.type()) {
case USER -> ...
case ADMIN -> ...
}
이렇게 변경하면서,
로그인 정책의 분기 기준은 다시
컴파일 타임에 검증 가능한 형태로 돌아왔다.
간단하게 정리하면
나만의 커스텀 단어 오타 채점기
그래서 코드를 전면 수정했다.
@Aspect
@Component
publicclassLoginCheckAspect {
@Around("@annotation(loginCheck)")
public ObjectcheckLogin(
ProceedingJoinPoint pjp,
LoginCheck loginCheck
)throws Throwable {
// 1. 웹 요청인지 확인
ServletRequestAttributesattrs=
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attrs ==null) {
thrownewIllegalStateException("No request context");
}
// 2. request 획득
HttpServletRequestrequest= attrs.getRequest();
// 3. 세션 획득 (없으면 null)
HttpSessionsession= request.getSession(false);
if (session ==null) {
thrownewHttpStatusCodeException(
HttpStatus.UNAUTHORIZED,"No session") {};
}
// 4. 타입별 로그인 정보 조회
String userId;
switch (loginCheck.type()) {
case USER -> userId = SessionUtil.getLoginUserId(session);
case ADMIN -> userId = SessionUtil.getLoginAdminId(session);
default ->thrownewIllegalStateException("Unknown type");
}
if (userId ==null) {
thrownewHttpStatusCodeException(
HttpStatus.UNAUTHORIZED,"NO_LOGIN") {};
}
return pjp.proceed();
}
}
@Around("@annotation(loginCheck)")
public ObjectcheckLogin(..., LoginCheck loginCheck)
이 loginCheck는:
리플랙션이 뭐지?
솔직히 말하면 이 구조도 완벽하지 않다.
getLoginUserId()
getLoginAdminId()
여전히:
이렇게 가야 한다.
다음 주에 공부할 범위가 자연스럽게 늘어났다.
https://www.youtube.com/watch?v=xsmKOo-sJ3c&list=PLJkjrxxiBSFALedMwcqDw_BPaJ3qqbWeB
Throwable,JWT 에 대한 블로그 딱 1개 찾아보기
Linking에 적용된 역 정규화 테이블 찾고 정규화 해보기
-> join 얼마나 차이나는지 AI한테물어보기
유효성 검사, 전역 예외처리 코드 추가하기
할 일 구체적으로 정하기
CORS는 저도 백엔드 연결때마다 겪는 문제인 것 같아요
제가 했던 프로젝트에서는 여기서 막혀서 해결하는데 시간이 꽤 걸렸던 기억이 있는데 잘 해결하신 것 같네요!!