분류 전체보기 1341

Ch07. 로그인 처리(필터, 인터셉터) - 서블릿 필터

공통 관심 사항 로그인하지 않은 사용자가 URL을 직접 입력하면 상품 관리 화면에 들어갈 수 있는 문제가 있다. 상품 관리 컨트롤러에서 로그인 여부를 체크하는 로직을 하나하나 작성하면 되겠지만, 등록, 수정, 삭제, 조회 등등 상품관리의 모든 컨트롤러 로직에 공통으로 로그인 여부를 확인해야 한다. 더 큰 문제는 향후 로그인과 관련된 로직이 변경될 때 작성한 모든 로직을 수정해야 할 수 있다. 이러한 공통 관심사는 스프링의 AOP로도 해결할 수 있지만, 웹과 관련된 공통 관심사는 지금부터 설명할 서블릿 필터 또는 스프링 인터셉터를 사용하는 것이 좋다 웹과 관련된 공통 관심사를 처리할 때는 HTTP의 헤더나 URL의 정보들이 필요한데, 서블릿 필터나 스프링 인터셉터는 HttpServletRequest를 제공..

Ch06. 로그인 처리(쿠키, 세션) - 세션 정보와 타임아웃 설정

세션은 사용자가 로그아웃을 직접 호출해서 session.invalidate()가 호출되는 경우에 삭제된다. 그런데 대부분의 사용자는 로그아웃을 선택하지 않고, 그냥 웹 브라우저를 종료한다. 문제는 HTTP가 비 연결성(ConnectionLess)이므로 서버 입장에서는 해당 사용자가 웹 브라우저를 종료한 것인지 아닌지를 인식할 수 없다. 따라서 서버에서 세션 데이터를 언제 삭제해야 하는지 판단하기가 어렵다. 이 경우 남아있는 세션을 무한정 보관하면 다음과 같은 문제가 발생할 수 있다. 세션과 관련된 쿠키( JSESSIONID )를 탈취 당했을 경우 오랜 시간이 지나도 해당 쿠키로 악의적인 요청을 할 수 있다. 세션은 기본적으로 메모리에 생성된다. 메모리의 크기가 무한하지 않기 때문에 꼭 필요한 경우만 생성..

Ch06. 로그인 처리(쿠키, 세션) - 로그인 처리하기

세션 동작 방식 앞서 쿠키에는 여러 보안 이슈가 있었다. 이 문제를 해결하기 위해서는 중요한 정보는 모두 서버에 저장해야 한다. 클라이언트와 서버는 추정 불가능한 임의의 식별자 값으로 연결해야 한다. 이렇게 서버에 중요한 정보를 보관하고 연결을 유지하는 방법을 세션이라고 한다. 클라이언트와 서버는 결국 쿠키로 연결되어야 한다. 서버는 클라이언트에 mySessionId라는 이름으로 세션 ID 만 쿠키에 담아서 전달한다. 클라이언트는 쿠키 저장소에 mySessionId 쿠키를 보관한다 클라이언트는 요청 시 항상 mySessionId 쿠키를 전달한다. 서버에서는 클라이언트가 전달한 mySessionId 쿠키 정보로 세션 저장소를 조회해서 로그인 시 보관한 세션 정보를 사용한다. 정리 쿠키 값을 변조 가능 ->..

Ch06. 로그인 처리(쿠키, 세션) - 쿠키와 보안 문제

보안 문제 쿠키 값은 임의로 변경할 수 있다. 클라이언트가 쿠키를 강제로 변경하면 다른 사용자가 된다. 실제 웹브라우저 개발자 모드 -> Application Cookie 변경으로 확인 Cookie: memberId=1 -> Cookie: memberId=2 (다른 사용자의 이름이 보임) 쿠키에 보관된 정보는 훔쳐갈 수 있다. 만약 쿠키에 개인정보나, 신용카드 정보가 있다면? 이 정보가 웹 브라우저에도 보관되고, 네트워크 요청마다 계속 클라이언트에서 서버로 전달된다. 쿠키의 정보가 나의 로컬 PC가 털릴 수도 있고, 네트워크 전송 구간에서 털릴 수도 있다. 해커가 쿠키를 한번 훔쳐가면 평생 사용할 수 있다. 해커가 쿠키를 훔쳐가서 그 쿠키로 악의적인 요청을 계속 시도할 수 있다 대안 쿠키에 중요한 값을 ..

Ch06. 로그인 처리(쿠키, 세션) - 로그인 처리하기(쿠키 사용)

로그인 상태를 유지하기 위해 쿠키를 사용 모든 요청에 쿠키 정보가 포함이 된다. 쿠키에는 영속 쿠키와 세션 쿠키가 있다. 영속 쿠키 : 만료 날짜를 입력하면 해당 날짜까지 유지 세션 쿠키 : 만료 날짜를 생략하면 브라우저 종료 시까지만 유지 쿠키 생성하기 - LoginController @PostMapping("/login") public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response){ if(bindingResult.hasErrors()){ return "login/loginForm"; } Member loginMember = loginService.lo..

Ch06. 로그인 처리(쿠키, 세션) - 로그인 기능

LoginService @Service @RequiredArgsConstructor public class LoginService { private final MemberRepository memberRepository; /** * @return null 로그인 실패 */ public Member login(String loginId, String password){ /* Optional findMemberOptional = memberRepository.findByLoginId(loginId); Member member = findMemberOptional.get(); if(member.getPassword().equals(password)){ return member; }else{ return nul..

Ch06. 로그인 처리(쿠키, 세션) - 회원 가입

Member 도메인 만들기 @Data public class Member { private Long id; @NotEmpty private String loginId; //로그인 ID @NotEmpty private String name; //사용자 이름 @NotEmpty private String password; } MemberRepository 만들기 @Slf4j @Repository public class MemberRepository { private static Map store = new HashMap(); //static 사용 private static long sequence = 0L; //static 사용 public Member save(Member member) { member.se..

Ch06. 로그인 처리(쿠키, 세션) - 로그인 요구사항 & 프로젝트 구조

요구사항 화면 - 로그인 전 회원 가입 로그인 홈 화면 - 로그인 후 본인 이름(누구님 환영합니다.) 상품 관리 로그 아웃 보안 요구사항 로그인 사용자만 상품에 접근하고, 관리할 수 있음 로그인하지 않은 사용자가 상품 관리에 접근하면 로그인 화면으로 이동 회원 가입, 상품 관리 프로젝트 구조 도메인이 가장 중요하다. 도메인 = 화면, UI, 기술 인프라 등등의 영역은 제외한 시스템이 구현해야 하는 핵심 비즈니스 업무 영역을 말함 web - domain 영역을 분리 domain item member login web item member login 향후 Web 기술을 변경하여도 도메인은 그대로 유지할 수 있어야 한다. web은 도메인을 알고 있지만 domain은 Web을 모르도록 설계해야 한다. web패키..

Ch05. 검증(Bean Validation) - Bean Validation(HTTP 메시지 컨버터)

@Valid , @Validated는 HttpMessageConverter ( @RequestBody )에도 적용할 수 있다. 참고 @ModelAttribute 는 HTTP 요청 파라미터(URL 쿼리 스트링, POST Form)를 다룰 때 사용한다. @RequestBody 는 HTTP Body의 데이터를 객체로 변환할 때 사용한다. 주로 API JSON 요청을 다룰 때 사용한다 @Slf4j @RestController @RequestMapping("/validation/api/items") public class ValidationItemApiController { @PostMapping("/add") public Object addItem(@RequestBody @Validated ItemSaveFor..

Ch05. 검증(Bean Validation) - Form 전송 객체 분리

실무에서는 groups를 잘 사용하지 않는데, 그 이유가 다른 곳에 있다. 바로 등록 시 폼에서 전달하는 데이터가 Item 도메인 객체와 딱 맞지 않기 때문이다 소위 "Hello World" 예제에서는 폼에서 전달하는 데이터와 Item 도메인 객체가 딱 맞는다. 하지만 실무에서는 회원 등록 시 회원과 관련된 데이터만 전달받는 것이 아니라, 약관 정보도 추가로 받는 등 Item과 관계없는 수많은 부가 데이터가 넘어온다. 그래서 보통 Item 을 직접 전달받는 것이 아니라, 복잡한 폼의 데이터를 컨트롤러까지 전달할 별도의 객체를 만들어서 전달한다. 예를 들면 ItemSaveForm이라는 폼을 전달받는 전용 객체를 만들어서 @ModelAttribute로 사용한다. 이것을 통해 컨트롤러에서 폼 데이터를 전달받고..