Skip to content

Latest commit

 

History

History
365 lines (224 loc) · 13.3 KB

TIL220330.md

File metadata and controls

365 lines (224 loc) · 13.3 KB

Daily to do list

Java


Spring


CS


알고리즘


오늘의 회고

220330 Spring MVC

—————————— 로그인

로그인 요구사항 홈 화면 - 로그인 전 회원 가입 로그인 홈 화면 - 로그인 후 본인 이름(누구님 환영합니다.) 상품 관리 로그 아웃 보안 요구사항 로그인 사용자만 상품에 접근하고, 관리할 수 있음 로그인 하지 않은 사용자가 상품 관리에 접근하면 로그인 화면으로 이동 회원 가입, 상품 관리

—————————— 패키지 구조 설계

  • 도메인이 가장 중요하다 도메인 = 화면, UI, 기술 인프라 등등의 영역을 제외한 시스템이 구현해야 하는 핵심 비즈니스 업무 영역을 말함.

웹과 도메인을 나눠 놓음. 향후 web을 다룬 기술로 바꾸어도 도메인은 그대로 유지할 수 있어야 한다. Web은 바뀌더라도 도메인 부분은 최대한 유지하여야 한다. 이렇게 하려면!!! web은 domain을 알고 있지만 domain은 web을 모르도록 설계해야 한다. 즉 web>domain 의존, domain>web 의존xx 즉 web에 있는 것들이 domain에 있는 것들을 써도 되지만. domain에 있는 것들은 web을 사용하지 않는다! web을 다 삭제해도 domain에는 전혀 영향이 없도록

 loginID 를 찾는 과정인데 이렇게 람다식을 사용하게 되면 훨씬 간편하게 구현이 가능하다.

  • Optional타입으로 하면 null이 나올 경우 empty()로 예외 처리가 가능.

 @ModelAttribute는 이렇게 이름을 안적으면 객체 이름에다가 제일 앞을 소문자로 변경해서 이름으로 해준다. 결국 위 아래 똑같음!

** 원래는 Member 하나의 클래스를 만드는 것이 아닌 addMemberForm, updateMemberForm 이런식으로 용도에 맞게 나누는 것이 맞으나 지금은 예제이므로 안했음.

 **********중요 옵셔널에서 .get(); 을 해야지 옵셔널에서 값이 나옴

자바8의 옵셔널, 람다, 스트림

 아이디나 비밀번호가 틀리면 reject로 로그인 에러를 처리. 이 오류는 필드만 봐서 되는것도 아니고 이 멤버 객체 만으로 판단하는것도 아님, 그렇기에 글로벌 오류로 반환함

———————————————————— 로그인 처리하기 - 쿠키 사용

  • 로그인 상태 유지하기 서버에서 로그인이 성공하면 HTTP 응답에 쿠키를 담아서 그러면 브라우저는 앞으로 해당 쿠키를 지속해서 보내준다.

 일단 기본적으로 보안 생각하지 않고 이러한 경우로 구현을 시작. 쿠키를 서버가 주고 클라이언트는 계속 쿠키를 전달하게 된다.  이렇게 모든 요청에 쿠키를 담아서 보낸다.

영속 쿠키 : 만료 날짜를 입력하면 해당 날짜까지 유지 세션 큐키 : 만료 날짜가 생략하면 브라우저 종료까지

로그인은 세션 쿠키

 로그인시 이렇게 쿠키를 전달

 로그아웃 요청이 들어오면 이전 로그인 쿠키의 값을 maxAge를 0으로 바꿔서 다시 전달한다. 이것을 클라이언트가 아닌 서버에서 하는 이유는 클라이언트가 만료된 쿠키를 갖고 있을수도 있고 잘못된 쿠키를 갖고 있어서 검증을 서버가 해주는 느낌으로 생각하면 된다.

———————————— 쿠키와 보안 문제

보안이.. 아까 방법은 당연히 보안이 너무 심함..

  1. 쿠키 임의 변경 가능, 그냥.. 위변조 쉽게 가능
  2. 쿠키에 보관된 정보는 훔쳐갈 수 있다, 쿠키에 개인정보, 신용카드 정보가 있다면?..
  3. 해커가 쿠키를 한번 훔쳐가면 평생 사용할 수 있다.
  • 대안
  1. 쿠키에 중요한 값을 노출하지 않고, 사용자 별로 예측 불가능한 임의의 토큰(랜덤값)을 노출하고, 서버에서 토큰과 사용자 id를 매핑해서 인식한다. 그리고 서버에서 토큰을 관리한다.
  2. 토큰은 해커가 임의의 값을 넣어도 찾을 수 없도록 예상 불가능 해야 한다.
  3. 해커가 토큰을 털어가도 시간이 지나면 사용할 수 없도록 해야 한다. 해당 토큰의 만료시간을 짧게(ex 30분) 유지한다. 또는 해킹 의심되는 경우 서버에서 해당 토큰을 제거한다.

이런 것을 세션으로 해결 가능.

—————————————— 중요한 정보는 모두 서버에 저장해야 한다!

이걸 세션

 세션ID를 생성하는데, 추정 불가능해야 한다!

  • 클라이언트와 서버는 결국 쿠키로 연결이 되어야 한다.. 서버는 클라이언트에 mySeesionId라는 이름으로 세션ID만 담은 쿠키를 담아서 전달. 클라이언트는 이것을 보관

************ 중요 여기서 중요한 포인트는 회원과 관련된 정보는 전혀 클라이언트에 전달하지 않는다는 것 오직 추정 불가능한 세션 ID만 쿠키를 통해 클라이언트에 전달.

정리 세션을 사용해서 서버에서 중요한 정보를 관리하게 되었다. 그래서 다음 문제를 해결

  • 쿠키 값을 변조 가능 >> 예상 불가능한 복잡한 세션ID를 사용한다.
  • 쿠키에 보관하는 정보는 클라이언트 해킹 시 털릴 가능성이 있다, >> 세션ID가 털려도 여기에는 중요한 정보가 없다.
  • 쿠키 탈취 후 사용 >> 해커가 토큰을 털어가도 시간이 지나면 사용할 수 없도록 세션의 만료 시간을 짧게 유지

——————————————————— 세션 직접 만들기

  • 세션 생성 session 생성, 세션 저장소에 session 저장, sessionID으로 응답 쿠키를 생성해서 클라에 전달 

  • 세션 조회 클라이언트가 요청한 sessionID쿠키의 값으로, 세션 저장소에 보관할 값 조회 

  • 세션 만료 클라이언트가 요청한 sessionID쿠키의 값으로, 세션 저장소에 보관한 sessionID와 값 제거 

  • 정리 세션이 뭔가 특별한 것이 아니라 단지 쿠키를 사용하는데 서버에서 데이터를 유지하는 방법일 뿐! 그런데 프로젝트마다 이러한 세션 개념을 직접 개발하는 것은 상당히 불편하다…..

그래서 서블릿도 세션 개념을 지원한다. 직접 만든 세션과 동작 방식과 거의 동일하다. 추가로 세션을 일정 시간 사용하지 않으면 해당 세션을 삭제하는 기능을 제공한다.

——————————————————— 로그인 처리하기 - 서블릿 HTTP 세션

서블릿도 세션을 위해 HttpSession을 제공한다. 

———————— TrackingModes

첫 로그인 실행 시 세션값이 URL에 붙게 된다. 웹 브라우저가 쿠키를 지원하지 않을 때 쿠키 대신에 URL을 통해 세션을 유지하는 방법.. URL에 이 값에 계속 유지해야하는데 거의 불가능

서버 입장에서는 클라가 쿠키를 지원하는지 몰라서 이렇게 둘 다 보내게 됨..

server.servlet.session.tracking-modes=cookie 이것을 프로퍼티에 설정

————————————————— 세션 정보와 타임아웃

 다양한 세션 정보가 온다. 

이것들을 조합해서 세션 타임아웃을 설정한다.

  • 세션 타임아웃 설정 세션은 사용자가 로그아웃을 직접 호출해서 session.invalidate()가 호출되는 경우에 삭제된다. 그런데 대부분의 사용자는 로그아웃을 선택하지 않고, 그냥 웹 브라우저를 종료한다.!

문제는 HTTP가 비 연결성이므로 서버 입장에서는 해당 사용자가 웹 브라우저를 종료한 것인지 아닌지를 인식 할 수 없다.!!! (세션은 메모리를 사용하고 있는데… )

이 경우 남아있는 세션을 무한정 보관하면<<

  1. 쿠키를 탈취 당했을 때 오랜 시간이 지나도 해당 쿠키로 악의적 요청 가능
  2. 세션은 기본적으로 메모리에 생성된다. 메모리의 크기가 무한하지 않기 때문에 꼭 필요한 경우만 사용해야 한다. (10만명의 사용자가 로그인하면 10만개의 세션;;;)
  • 세션 종료 시점 세션의 종료 시점은 어떻게 정하면 좋을지 ,,,, 가장 단순하게는 세션 생성 시점에서 30분정도 근데 사용자가 열심히 30분 넘게 돌아가면 또 로그인해야 한다?? 이건 사용자가 너무 불편…

더 나은 대안으로는 사용자가 서버에 최근에 요청한 시간을 기준으로 30분 정도를 유지해주는 것! 이렇게 하면 사용자가 서비스를 사용하고 있으면 세션의 생존 시간이 30분으로 계속 늘어난다. HttpSession은 이 방식을 사용!

  • 세션 타임아웃 발생 세션 타임아웃 시간은 해당 세션과 관련된 JSessionId를 전달하는 HTTP 요청이 있으면 현재 시간으로 다시 초기화 된다. session.getLastAccessedTime() == 최근 세션 접근 시간.

LastaAccsedTime 이후로 timeout시간이 지나면, WAS가 내부에서 해당 세션을 제거

  • 정리 서블릿의 HttpSession이 제공하는 타임아웃 기능 덕분에 세션을 안전하고 편리하게 사용 가능.

실무에서는 주의해야하는 점이 세션에는 최소한 정보만 보관해야한다. 보관한 데이터 용량 * 사용자 수로 세션의 메모리 사용량이 급격하게 늘어나서 장애로 이어질 수 있다. 추가로 세션의 시간을 너무 길게 가져가면 메모리 사용이 계속 누적 될 수 있으므로 적당한 시간을 선택해야 한다.

—————————————— 로그인 처리 - 필터 입터셉터

서블릿 필터

  • 공통 관심 사항 요구사항을 보면 로그인 한 사용자만 상품 관리가 가능. 상품 관리 컨트롤러에서 하나하나 로그인을 했는지 확인을 해야 함…. 너무 똑같은 기능을 반복해서 만들어야 한다..

이렇게 애플리케이션 여러 로직에서 공통으로 관심이 있는 것을 공통관심사 라고 한다.

이러한 공통 관심사는 스프링의 AOP로도 해결할 수 있지만 웹과 관련된 공통 관심사는 서블릿 필터 또는 스프링 인터셉터를 사용하는 것이 좋다. 웹과 관련된 공통 관심사를 처리할 떄는 HTTP헤더나 URL 정보가 필요한데 서블릿 필터나 스프링 인터셉터는 HTTPservletrequest를 제공한다.

  • 서블릿 필터 필터는 서블릿이 지원하는 수문장,

 필터를 적용하면 필터가 호출 된 다음에 서블릿이 호출된다.

필터는 특정 URL 패턴을 적용할 수 있다. 참고로 스프링을 사용하면 여기서 보는 서블릿은 디스패처 서블릿

  • 필터 제한 

필터에서 적절하지 않은 요청이라고 판단하면 거기서 끝을 낼 수 있다. 그래서 로그인 여부를 체크하기 딱 좋다.

  • 필터 체인  필터는 체인으로 구성되는데, 중간에 필터를 자유롭게 추가할 수 있다.

  • 필터 인터페이스 

——————————————— 요청 로그

 doFilter

참고 실무에서 HTTP 요청시 같은 로그에 모두 같은 식별자를 자동으로 남기고 싶다면 logback mdc 검색…

————————————————— 서블릿 필터 - 인증 체크

  이렇게 화이트 리스트도 만들어서 가능  스프링 시큐리티도 이런 방식..ㅎ

——————————— 스프링 인터셉터

스프링 인터셉터는 디스패처 섭를릿과 컨트로러 사이에서 컨트롤러 호출 직전에 호출 

인터셉터 제한, 체인도 사용 가능.

******* afterCOmpletion은 예외가 발생하여도 호출 된다.

서블릿 필터를 꼭 사용해야 하는 상황이 아니면 인터셉터를 사용하는 것이 편리.

———————————— 스프링 인터셉터 - 요청 로그

 인터셉터의 가장 큰 특징은 각각 분리가되어 있고. 핸들러 사용이 가능하다는 것이다. 그리고 HttpServletRequest로 와서 다운 캐스팅이 필요가 없다. 

필터와 비교해보면 인터셉터는 addPathPatterns, excludePathPatterns로 매우 정밀하게 URL 패턴을 지정할 수 있다.

 필요할 때 읽어보면 된다..

—————————————————— 스프링 인터셉터 - 인증 체크

 인터셉터의 큰 장점… 패턴을 이렇게 세밀하게 선택이 가능하다!!

 그렇기에 이렇게 로직이 짧아진다.

서블릿 필터와 비교해서 코드가 매우 간결, 인증이라는 것은 컨트롤러 호출 전에만 호출되면 된다. 따라서 preHandle만 구현하면 된다.

order() 순서 주의, 세밀한 설정 가능

————————————— ArgumentResolver 활용

컨트롤러에서 공통으로 사용하는 것을 애노테이션을 만드는 것.

 이렇게 바꿀 수 있음 @Login

 이렇게 애노테이션 만들고

 LoginMemberArgumentResolver를 만든다..! 

 등록까지 해야지 사용 가능

실행해보면 결과는 동일하지만 더 편리하게 로그인 회원 정보를 조회할 수 있다. 이렇게 ArgumentResolver를 활용하면 공통 작업이 필요할 떄컨트롤러를 더욱 편리하게 사용할 수 있다.

———————————————————————— 예외 처리와 오류 페이지