로그아웃 커스텀 처리
487
작성한 질문수 3
아래처럼 securityConfig에 커스텀 로그아웃 경로에 대해 어떠한 permitAll 같은 권한 설정을 하지 않았는데도 제가 작성한 컨트롤러까지 잘 들어가서 로그아웃처리가 됩니다. 왜 허용이 되어있는거죠? 별도로 로그아웃 경로에 대해 permitAll 하지 않으면 접근이 막혀야 하는 것 아닌가요?
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
@Bean
public AuthenticationProvider authenticationProvider() {
return new FormAuthenticationProvider(userDetailsService, passwordEncoder());
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations());
}
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/users").permitAll()
.antMatchers("/myPage").hasRole("USER")
.antMatchers("/messages").hasRole("MANAGER")
.antMatchers("/config").hasRole("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login_proc")
.defaultSuccessUrl("/")
.permitAll();
}
}
답변 1
0
네
일단 위의 코드에서는 커스텀한 로그아웃 설정이 보이지는 않습니다.
그리고 좀 더 부연 설명을 드리자면 스프링 시큐리티에서는 로그아웃 페이지를 자동 생성하는 필터를 제공하고 있습니다.
DefaultLogoutPageGeneratingFilter 필터입니다.
이 필터는 기본적으로 /logout url 로 요청하는 것에 대해서는 권한을 체크하기 앞서 로그아웃 페이지로 이동시켜 버립니다.
public class DefaultLogoutPageGeneratingFilter extends OncePerRequestFilter {
private RequestMatcher matcher = new AntPathRequestMatcher("/logout", "GET");
private Function<HttpServletRequest, Map<String, String>> resolveHiddenInputs = (request) -> Collections.emptyMap();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.matcher.matches(request)) {
renderLogout(request, response);
}
else {
if (logger.isTraceEnabled()) {
logger.trace(LogMessage.format("Did not render default logout page since request did not match [%s]",
this.matcher));
}
filterChain.doFilter(request, response);
}
}
private void renderLogout(HttpServletRequest request, HttpServletResponse response) throws IOException {
StringBuilder sb = new StringBuilder();
sb.append("<!DOCTYPE html>\n");
sb.append("<html lang=\"en\">\n");
sb.append(" <head>\n");
sb.append(" <meta charset=\"utf-8\">\n");
sb.append(" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n");
sb.append(" <meta name=\"description\" content=\"\">\n");
sb.append(" <meta name=\"author\" content=\"\">\n");
sb.append(" <title>Confirm Log Out?</title>\n");
sb.append(" <link href=\"https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css\" "
+ "rel=\"stylesheet\" integrity=\"sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M\" "
+ "crossorigin=\"anonymous\">\n");
sb.append(" <link href=\"https://getbootstrap.com/docs/4.0/examples/signin/signin.css\" "
+ "rel=\"stylesheet\" crossorigin=\"anonymous\"/>\n");
sb.append(" </head>\n");
sb.append(" <body>\n");
sb.append(" <div class=\"container\">\n");
sb.append(" <form class=\"form-signin\" method=\"post\" action=\"" + request.getContextPath()
+ "/logout\">\n");
sb.append(" <h2 class=\"form-signin-heading\">Are you sure you want to log out?</h2>\n");
sb.append(renderHiddenInputs(request)
+ " <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\">Log Out</button>\n");
sb.append(" </form>\n");
sb.append(" </div>\n");
sb.append(" </body>\n");
sb.append("</html>");
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write(sb.toString());
}
위의 코드를 보시면
if (this.matcher.matches(request)) {
renderLogout(request, response);
}
/logout 으로 요청하면 로그아웃 페이지를 렌더링한다는 구문입니다.
그리고 로그아웃 페이지를 만들고 있습니다.
또 한가지는 DefaultLoginPageGeneratingFilter 입니다.
로그인 페이지를 렌더링하는 필터인데 소스를 보면 이런 구문이 있습니다.
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
boolean loginError = isErrorPage(request);
boolean logoutSuccess = isLogoutSuccess(request);
if (isLoginUrlRequest(request) || loginError || logoutSuccess) {
String loginPageHtml = generateLoginPageHtml(request, loginError, logoutSuccess);
response.setContentType("text/html;charset=UTF-8");
response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);
response.getWriter().write(loginPageHtml);
return;
}
chain.doFilter(request, response);
}
위의 구문을 보시면 logoutSuccess 가 true 이면 로그인 페이지로 이동하도록 되어 있습니다.
즉 로그아웃 실행을 하게 되면 이 필터가 후속처리를 하고 있습니다.
그래서 전체적으로 보면 설정클래스에서 권한을 permitAll 로 정의하지 않았지만 로그인, 로그아웃 전용 필터가 앞서 요청을 가로채어 처리를 하고 있기 때문입니다.
로그인, 로그아웃 필터를 참고하시면 되겠습니다.
시큐리티 공부 버전 질문
0
176
1
[해결 방법] MethodSecurityConfig.customMethodSecurityMetadataSource() 호출하지 않는 이슈
0
187
1
AbstractSecurityInterceptor.class.beforeInvocation()를 2번 실행하는 경우
0
178
1
강의 코드가 왜이렇게 뒤죽박죽인가요...
0
251
1
메인 페이지로 접속해도 login url로 리다이렉트가 되지 않습니다..
0
237
1
파라미터값이 넘어가지 않습니다 ....
0
374
1
security filterChain 설정 질문이 있습니다.
0
332
1
소스 부분 질문 드립니다.
0
210
2
섹션4 7번 강의 문제가 있는거 같네요.
0
345
2
파일이 수시로 이름이 바껴있네요 ㄷㄷ
0
306
1
HttpSessionSecurityContextRepository를 사용안하는 문제
0
557
2
error , exception 이 잘 안됩니다.
0
284
2
thymeleaf tag 질문합니다.
0
198
2
버전업하면서 deprecated된 것들이 너무많아요
0
478
1
spring security 패치 관련
0
437
1
모바일을 사용할때 토큰말고 세션
0
848
2
DB 연동한 인가 부분에 대한 질문입니다!
0
265
1
Ajax방식도 똑같이 Session방식을 사용하는건가요?
0
308
1
Config 파일 생성 시 질문이 있습니다.
0
228
1
강사님 몇일동안 구글 검색만 100개 했는데도 이유를 모르겠습니다..
1
432
2
403 에러 뜹니다.
0
813
2
login_proc의 존재에 대한 간략한 설명입니다
0
277
1
top.html에 로그인 링크를 만들어서 로그인을 해봤습니다
0
287
2
안녕하세요. DB에 저장될 때 이해 안 가는 값이 있어서 질문드립니다!
0
191
1





