Home

0

Spring Security - Remember Me와 관련된 인증 API - RememberMeConfigurer

목차 Spring Security 권한 계층 사용하기 - @RoleHierarcy Spring Security - DelegateFilterProxy Spring Security - Remember Me와 관련된 인증 API - RememberMeConfigurer Spring Security - RembmerMeAuthenticationFilter Spring Security - SessionManagementFilter & ConcurrentSessionFilter Spring Security - 인가 API ExpressionUrlAuthorizationConfigurer Spring Security - Security 설정을 위한 WebSecurityConfigurerAdatper Spring Security - AuthenticationProvider Spring Security - AuthenticationManager Spring Security - UsernamePasswordAuthenticationFilter & AbstractAuthenticationProcessingFilter Spring Security - SecurityContextHolder 와 SecurityContext Spring Security - Authentication 객체 Remember Me와 관련된 인증 API rememberMeParameter 쿠키의 파라미터명을 지정한다. 체크박스의 이름(parameter)과 remember-me의 파라미터 명은 일치 시켜줘야 한다. tokenValiditySeconds 쿠키의 만료시간을 설정한다. useSecureCookie Cookie 에 보안 설정을 할 때 사용하는 Flag HTTPS 환경에서만 사용할 수 있다. userDetailsService remember-me 를 이용한 인증 진행시 시스템의 사용자 계정을 조회할 때 사용하는 class 를 지정한다. tokenRepository Remember Me Token 저장소를 설정한다. 기본은 TokenBasedRememberMeServices 를 사용하기 때문에 Cookie 에 저장하는 방식이다. 기본 구현체는 InMemoryTokenRepositoryImpl 와 JdbcTokenRepositoryImpl 로 저장소를 명시해주면 PersistentTokenBasedRememberMeServices 를 사용한다. key Remember Me Authentication 객체 유효성을 확인하기 위한 Key 값을 설정한다. String Hash 비교를 통해 인증 유효성을 확인한다. alwaysRemember Remember Me 기능이 활성화되지 않아도 항상 실행하는 Flag 사용자의 Session이 생성되었고 Session이 인증 객체를 담고 있다는 것이다. RememberMeConfigurerpublic RememberMeConfigurer<H> tokenValiditySeconds(int tokenValiditySeconds) { this.tokenValiditySeconds = tokenValiditySeconds; return this;}public RememberMeConfigurer<H> useSecureCookie(boolean useSecureCookie) { this.useSecureCookie = useSecureCookie; return this;}public RememberMeConfigurer<H> userDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; return this;}public RememberMeConfigurer<H> tokenRepository(PersistentTokenRepository tokenRepository) { this.tokenRepository = tokenRepository; return this;}public RememberMeConfigurer<H> key(String key) { this.key = key; return this;}public RememberMeConfigurer<H> rememberMeParameter(String rememberMeParameter) { this.rememberMeParameter = rememberMeParameter; return this;}public RememberMeConfigurer<H> rememberMeCookieName(String rememberMeCookieName) { this.rememberMeCookieName = rememberMeCookieName; return this;}public RememberMeConfigurer<H> rememberMeCookieDomain(String rememberMeCookieDomain) { this.rememberMeCookieDomain = rememberMeCookieDomain; return this;}public RememberMeConfigurer<H> authenticationSuccessHandler( AuthenticationSuccessHandler authenticationSuccessHandler) { this.authenticationSuccessHandler = authenticationSuccessHandler; return this;}public RememberMeConfigurer<H> rememberMeServices(RememberMeServices rememberMeServices) { this.rememberMeServices = rememberMeServices; return this;}public RememberMeConfigurer<H> alwaysRemember(boolean alwaysRemember) { this.alwaysRemember = alwaysRemember; return this;}

0

네트워크 - HTTP Status Code

HTTP Status Code1xx (Information) - 정보성 상태 코드 Http Status Code는 HTTP/1.1 에서 도입된 상태 코드 2xx (Successful) - 성공 상태 코드 코드 설명 200 : OK 요청 성공했음을 나타낸다. 201 : Created 요청이 성공하고 새로운 리소스가 생성됐음을 나타낸다. 202 : Accepted 요청은 성공했으나 서버가 아직 작업을 진행하지 않은 상태를 나타낸다. 204 : No Content 요청이 성공했고 Server에서 Client로 보낼 데이터가 없는 상태를 나타낸다. 3xx (Redirection) - 리다이렉션 상태 코드 코드 설명 300 : Multiple Choices 리소스의 URI가 영구적으로 이동 301 : Moved Permanently 302 : Found 303 : See Other 304 : Not Modified 307 : Temporary Redirect 308 : Permanent Redirect 4xx (Client Error) - 클라이언트 오류

0

Spring MVC Request Life Cycle - Interceptor

목차 Spring MVC - ArgumentResolver Spring MVC Request Life Cycle - ViewResolver Spring MVC Request Life Cycle - HandlerAdapter Spring MVC Request Life Cycle - HandlerMapping Spring MVC Request Life Cycle - DispatcherServlet Spring MVC Request Life Cycle - Interceptor Spring MVC Request Life Cycle - Filter Interceptor 스프링 Interceptor 는 Handler(Controller) 호출 전, 후에 사용자 요청 및 응답을 가로채 특정 로직을 수행하는 역할을 한다. DispatcherServlet 이후에 동작한다. 스프링 Filter 처럼 Request, Response 객체를 다른 객체로 변경하는 것이 불가능 하다. Interceptor 는 Request, Response 객체를 넘겨주는 방식으로 진행하지 않고, boolean 값을 반환하는 형태로 로직 수행 Interceptor 인터페이스 preHandle Handler 호출 전에 실행된다. HttpServletRequest 객체를 이용해 preHandle 이 true 를 반환하면 다음으로 진행하고, false 면 진행하지 않는다. postHandle Handler 호출 후에 실행된다. afterCompletion View 가 렌더링 된 이후에 호출된다. public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { }}

0

Spring Boot - HttpSession 사용하기

목차 Spring Boot - HttpSession 사용하기 Spring Boot - 직접 Session Storage 구현하기 Spring Boot - Cookie 사용하기 Spring boot Session 사용하기 2 request.getSession(true) HttpSession 이 존재하면 HttpSession 을 반환하고 존재하지 않으면 새로운 Session 을 반환한다. request.getSession(false) HttpSession 이 존재하면 현재 HttpSession 을 반한하고 존재하지 않으면 null 을 반환한다. @PostMapping("/login")public String loginV3(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletRequest request){ log.info("Request Params : {}", form); if(bindingResult.hasErrors()){ return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if(loginMember == null){ bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다."); return "login/loginForm"; } // 로그인 설공 처리 TODO // 세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성 HttpSession session = request.getSession(); // 세션에 로그인 회원 정보를 보관 session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember); return "redirect:/";} @PostMapping("/logout")public String logoutV3(HttpServletRequest request){ HttpSession session = request.getSession(false); if(session != null){ session.invalidate(); } return "redirect:/";} @GetMapping("/")public String homeLoginV3(HttpServletRequest request, Model model){ HttpSession session = request.getSession(false); if(session == null){ return "home"; } Member LoginMember = (Member) session.getAttribute(SessionConst.LOGIN_MEMBER); // 세션에 회원 데이터가 없으면 home if(LoginMember == null){ return "home"; } // 세션이 유지되 로그인으로 이동 model.addAttribute("member", LoginMember); return "loginHome";} 스프링에서 지원하는 Session 기능 사용하기@GetMapping("/")public String homeLoginV3Spring( @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, Model model){ // 세션에 회원 데이터가 없으면 home if(loginMember == null){ return "home"; } // 세션이 유지되 로그인으로 이동 model.addAttribute("member", loginMember); return "loginHome";}

0

Spring Boot - 직접 Session Storage 구현하기

목차 Spring Boot - HttpSession 사용하기 Spring Boot - 직접 Session Storage 구현하기 Spring Boot - Cookie 사용하기 직접 만든 Session 사용하기@Componentpublic class SessionManager { public static final String SESSION_COOKIE_NAME = "mySessionId"; private Map<String, Object> sessionStore = new ConcurrentHashMap<>(); public void createSession(Object value, HttpServletResponse response){ // Session id를 상성하고 값을 Session에 저장 String sessionId = UUID.randomUUID().toString(); // Session Store 에 새로운 Session 정보를 저장한다. // Session 은 Key Value 형태로 데이터를 저장 sessionStore.put(sessionId, value); // 쿠키 생성 // Session Id 를 Cookie 에 넣어 전달한다. Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId); response.addCookie(mySessionCookie); } public Object getSession(HttpServletRequest request){ // Request 에서 Session Id 를 가져온다. Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME); if(sessionCookie == null){ return null; } // Session Store 에 저장된 Session 정보를 가져온다. return sessionStore.get(sessionCookie.getValue()); } public void expire(HttpServletRequest request){ Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME); if(sessionCookie != null){ sessionStore.remove(sessionCookie.getValue()); } } public Cookie findCookie(HttpServletRequest request, String cookieName){ if(request.getCookies() == null){ return null; } return Arrays.stream(request.getCookies()) .filter(cookie -> cookie.getName().equals(cookieName)) .findAny() .orElse(null); }} @PostMapping("/login")public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response){ log.info("Request Params : {}", form); if(bindingResult.hasErrors()){ return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if(loginMember == null){ bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다."); return "login/loginForm"; } // 로그인 설공 처리 TODO // 쿠키 사용하기 // 쿠키에 시간 정보를 주지 않으면 세선 쿠(브라우저 종료시 모두 종료) Cookie cookie = new Cookie("memberId", String.valueOf(loginMember.getId())); response.addCookie(cookie); return "redirect:/";} Testclass SessionManagerTest { SessionManager sessionManager = new SessionManager(); @Test void SessionTest(){ // 세션 생성 MockHttpServletResponse response = new MockHttpServletResponse(); Member member = new Member(); sessionManager.createSession(member, response); // 요청에 응답 쿠키 저장 MockHttpServletRequest request = new MockHttpServletRequest(); request.setCookies(response.getCookies()); // 세션 조회 Object result = sessionManager.getSession(request); assertThat(result).isEqualTo(member); // 세션 만료 sessionManager.expire(request); Object expired = sessionManager.getSession(request); assertThat(expired).isNull(); }} @PostMapping("/login")public String loginV2(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response){ log.info("Request Params : {}", form); if(bindingResult.hasErrors()){ return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if(loginMember == null){ bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다."); return "login/loginForm"; } // 로그인 설공 처리 TODO // 세션 관리자를 통해 세션을 생성하고, 회원 데이터 보관 // 쿠키에 시간 정보를 주지 않으면 세션 쿠키(브라주어 종료시 모두 종료) sessionManager.createSession(loginMember, response); return "redirect:/";} @PostMapping("/logout")public String logoutV2(HttpServletRequest request){ sessionManager.expire(request); return "redirect:/";}

0

Spring Boot - Cookie 사용하기

목차 Spring Boot - HttpSession 사용하기 Spring Boot - 직접 Session Storage 구현하기 Spring Boot - Cookie 사용하기 쿠키 생성스프링에서 쿠키는 Cookie 를 이용해 쉽게 생성할 수 있습니다. 생성한 쿠키를 Client 로 전달하기 위해 컨트롤러 메소드 파라미터로 HttpServletResponse 객체를 추가한 후 HttpServletResponse 객체에 생성한 쿠키를 넣어줍니다. @GetMapping("/cookie/create")public ResponseEntity<String> helloCookie(HttpServletResponse httpServletResponse) { Cookie cookie = new Cookie("helloCookie", URLEncoder.encode("Hello world", StandardCharsets.UTF_8)); httpServletResponse.addCookie(cookie); return ResponseEntity.ok().body("Create Cookie");} 쿠키 생성 테스트@Testvoid CookieTest() throws Exception { ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders.get("/cookie/create")) .andExpect(status().isOk()) .andExpect(cookie().exists("helloCookie")) .andExpect(cookie().value("helloCookie", "Hello+world")) .andDo(print());} TestRestTemplate 을 이용해 어플리케이션에 대한 컨트롤러 테스트를 진행합니다. Client 로 전달된 쿠키는 Response Header 에서 확인할 수 있습니다. @LocalServerPortprivate int port;@Autowiredprivate TestRestTemplate restTemplate;@Testvoid helloCookie() { String url = "http://localhost:" + port + "/cookie/create"; // 테스트할 엔드포인트 URL // REST API 호출 ResponseEntity<String> response = restTemplate.getForEntity(url, String.class); // 응답 헤더에서 쿠키 정보 가져오기 HttpHeaders headers = response.getHeaders(); List<String> cookies = headers.get(HttpHeaders.SET_COOKIE); assertThat(response.getBody()).isEqualTo("Create Cookie"); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); for (String cookie : cookies) { System.out.println("cookie = " + cookie); assertThat(cookie.contains("helloCookie")).isTrue(); }}

0

백준 14592 - 연구소

백준 14592 - 연구소https://www.acmicpc.net/problem/14592 문제풀이해당 문제에서는 3가지 입력 N, M, 지도 모양이 주어진다. N : 세로 크기 M : 가로 크기 지도 정보 지도 내 상태는 3가지 상태가 존재한다. 0 : 빈칸 1 : 벽 2 : 바이러스 알고리즘 실행계획은 다음과 같이 진행한다. 벽을 세운다. 바이러스 확산 시킨다. 바이러스 영역을 확인한다.

0

백준 1158 - 요세푸스 문제

백준 1158 - 요세푸스 문제https://www.acmicpc.net/problem/1158 문제 풀이해당 문제에서는 두가지 입력 N, K가 주어진다. N : 사람 수 K : 원에서 사람이 제거되는 간격 N, K의 최대 5000 이므로, 최대 O(N^2)의 시간복잡도내에서 문제를 해결해야 한다. 전체 소스 코드import java.io.*;import java.util.*;public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] arguments = br.readLine().split(" "); int N, K; N = Integer.parseInt(arguments[0]); K = Integer.parseInt(arguments[1]); List<Integer> list = new ArrayList<>(); for (int i = 0; i < N; i++) { list.add(i + 1); } int index = 0; StringBuilder sb = new StringBuilder(); sb.append("<"); // 사람을 간격에 맞게 하나씩 제거해준다. while (list.size() > 1) { index += K - 1; index %= list.size(); int removedValue = list.remove(index); sb.append(Integer.toString(removedValue)); sb.append(", "); } // 마지막 숫자를 제거한다. index += K - 1; index %= list.size(); int removedValue = list.remove(index); sb.append(Integer.toString(removedValue)); sb.append(">"); System.out.println(sb.toString()); br.close(); }}

0

Spring Boot - Resource 추상화

목차 Spring Boot - StreamingResponseBody Spring Boot - ResourceRegion Spring Boot - 파일 다운로드 서비스 구현하기 Spring Boot - 파일 업로드 서비스 구현하기 Spring Boot - Resource 추상화 Spring Boot - MultipartFile 에서 발생하는 예외 처리 Spring Boot - MultipartFile 를 이용한 파일 업로드 Spring Boot - Part 객체를 이용한 파일 업로드 Spring boot Resource 추상화https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/resources.html Resource 는 java.net.URL 을 추상화 해 스프링 프레임워크에서 Low-Level에 있는 자원에 쉽게 접근할 수 있도록 지원한다 ClassPath를 기준으로 리소스를 가져오는 기능의 부재 ServletContext를 기준으로 상대 경로를 읽어오는 기능의 부재 Resource.java public interface Resource extends InputStreamSource { boolean exists(); URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; @Nullable String getFilename(); String getDescription(); default boolean isReadable() { return exists(); } default boolean isOpen() { return false; } default boolean isFile() { return false; } default ReadableByteChannel readableChannel() throws IOException { return Channels.newChannel(getInputStream()); }} Resource 구현체

0

Spring Boot - 파일 다운로드 서비스 구현하기

목차 Spring Boot - StreamingResponseBody Spring Boot - ResourceRegion Spring Boot - 파일 다운로드 서비스 구현하기 Spring Boot - 파일 업로드 서비스 구현하기 Spring Boot - Resource 추상화 Spring Boot - MultipartFile 에서 발생하는 예외 처리 Spring Boot - MultipartFile 를 이용한 파일 업로드 Spring Boot - Part 객체를 이용한 파일 업로드 파일 다운로드를 위한 HTTP 해더서버에 저장된 파일을 다운 받기 위해서는 Response 해더에 Content-Disposition 정보가 필요합니다. Content-Disposition 는 HTTP 프로토콜에서 사용되는 헤더로, 서버가 클라이언트에게 제공하는 콘텐츠가 브라우저에 표시될지 또는 다운로드할지, 그리고 다운로드될 경우 파일 이름은 무엇인지 등을 지정합니다. Content-Disposition 는 inline, attachment 두 가지 종류가 있습니다. Content-Disposition 값이 inline 면 콘텐츠가 브라우저에서 직접 표시됩니다. attachment 면 콘텐츠가 다운로드를 위한 파일로 제공됩니다. filename 속성을 이용하면 다운로드하기 위한 파일이름을 지정할 수 있습니다. // Content-Disposition 값이 inline 일 경우 브라우저에 직접 표시됩니다.Content-Disposition: inline// attachment 일 경우 리소스를 파일로 다운로드할 수 있습니다. filename 속성을 통해 파일 이름을 지정할 수 있습니다.Content-Disposition: attachment; filename="example.txt" 리소스 다운로드 서비스 구현리소스를 반환하는 Response 객체에 Content-Disposition 해더를 추가해줍니다.