스프링 시큐리티 시리즈
- Spring Boot: 시큐리티(Security) – 1
- Spring Boot: 시큐리티(Security) – 2 – 커스텀 로그인 페이지 만들기
- Spring Boot: 시큐리티(Security) – 3 – 로그인 및 권한 정보를 DB에서 가져오기
- Spring Boot: 시큐리티(Security) – 4 – 로그인 폼을 거치지 않고 컨트롤러에서 로그인
- Spring Boot: 시큐리티(Security) – 5 – 권한별 접근 가능한 페이지를 데이터베이스에 설정하기 (동적 설정)
- Spring Boot Security OAuth2: 커스텀 로그인 페이지 구현
1. SecurityConfig 클래스의 configure(http) 에 다음 내용을 추가합니다.
.formLogin().loginPage("/login").failureUrl("/login?error").permitAll() // .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .addLogoutHandler(new TaskImplementingLogoutHandler()).permitAll().logoutSuccessUrl("/");
loginPage
는 로그인할 페이지의 주소이며 로그인이 필요한 상황에서 localhost:xxx/login 을 통해 로그인 화면으로 접속합니다. failureUrl
은 로그인 실패했을 때 나타나는 뷰 페이지의 주소입니다. permitAll()
이 없으면 권한 문제가 있는 경우 로그인 화면에 들어갈 수 없으므로 반드시 넣어줘야 합니다. loginSuccessUrl
은 로그인 성공했을 시 이동할 주소입니다.
2021-01-21 추가: loginSuccessUrl이라는 메소드는 없으며 defaultSuccessUrl
나 successForwardUrl
을 한다고 합니다. 주로 전자가 많이 사용된다고 합니다. (둘의 차이점)
.logoutRequestMatcher(new AntPathRequestMatcher("/로그아웃 주소))
는 로그아웃을 실행할 주소입니다. 주소창에 localhost:xxx/logout을 입력하면 로그아웃이 될 것입니다. .addLogoutHandler(new TaskImplementingLogoutHandler())
는 로그아웃 시 실행할 작업을 입력하며 해당 클래스는 아래에 있습니다. logoutSuccessUrl
은 로그아웃 성공시 이동할 주소이다. 만약 logoutSuccessUrl("/login?logout")
을 입력하면 루트 페이지 대신 해당 페이지로 접속하게 됩니다.
이것들을 반영한 SecurityConfig
클래스는 아래와 같습니다.
package com.example.security; import org.springframework.context.annotation.Bean; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/adminOnly").hasAuthority("ROLE_ADMIN") .antMatchers("/**").permitAll() // 넓은 범위의 URL을 아래에 배치한다. .anyRequest().authenticated() .and() .formLogin().loginPage("/login").failureUrl("/login?error").permitAll() .defaultSuccessUrl("/") .and() .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .addLogoutHandler(new TaskImplementingLogoutHandler()).permitAll().logoutSuccessUrl("/"); // 로그아웃 기본 url은 (/logout) // 새로 설정하려면 .logoutUrl("url") 사용 } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("admin").password(passwordEncoder().encode("1234")).roles("ADMIN") .and() .withUser("guest").password(passwordEncoder().encode("guest")).roles("GUEST"); } // passwordEncoder() 추가 @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
2. TaskImplementingLogoutHandler 클래스를 작성합니다.
package com.example.security; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.web.authentication.logout.LogoutHandler; public class TaskImplementingLogoutHandler implements LogoutHandler { Logger logger = LoggerFactory.getLogger(TaskImplementingLogoutHandler.class); @Override public void logout(HttpServletRequest req, HttpServletResponse res, Authentication authentication) { logger.info("로그아웃 되었습니다."); } }
로그아웃 시 필요한 작업을 logout
메소드 안에 작성합니다. 이 부분은 빈 메소드로 작성해도 상관없고, 애초에 클래스 작성이 필수가 아닙니다. Security.configure(http)에서 .addLogoutHandler(new TaskImplementingLogoutHandler())
부분을 제거하면 로그아웃 핸들러를 사용하지 않습니다. 다만 관리 측면에서 로그아웃 후 후속작업이 필요한 경우가 많기 때문에 핸들러를 만들어놓는 것이 좋습니다.
3. 컨트롤러에 다음을 추가합니다.
@RequestMapping("/login") public String loginForm() { return "login-form"; }
login
페이지를 스프링 기본이 아닌 사용자가 지정한 뷰 페이지로 이동하도록 합니다.
4. 로그인 뷰 페이지를 작성합니다.
<html xmlns:th="https://www.thymeleaf.org"> <head > <title>Please Login</title> </head> <body> <div th:fragment="content"> <form name="f" th:action="@{/login}" method="post"> <fieldset> <legend>Please Login</legend> <div th:if="${param.error}" class="alert alert-error"> Invalid username and password. </div> <div th:if="${param.logout}" class="alert alert-success"> You have been logged out. </div> <label for="username">Username</label> <input type="text" id="username" name="username"/> <label for="password">Password</label> <input type="password" id="password" name="password"/> <div class="form-actions"> <button type="submit" class="btn">Log in</button> </div> </fieldset> </form> </div> </body> </html>
src/main/resources/templates/login-form.html 파일을 작성합니다. 로그인 기능이 동작하게 하기 위해 폼 설정에서 th:action="@{/login}" method="post"
을 추가 하고, 아이디는 name="username"
, 비밀번호는 name="password"
로 설정합니다. param.error
, param.logout
은 로그인 에러 또는 로그아웃인 경우 해당 파라미터를 통해 로그인에 접속하면 메시지를 표시하는 역할을 합니다.
스프링 시큐리티 시리즈
- Spring Boot: 시큐리티(Security) – 1
- Spring Boot: 시큐리티(Security) – 2 – 커스텀 로그인 페이지 만들기
- Spring Boot: 시큐리티(Security) – 3 – 로그인 및 권한 정보를 DB에서 가져오기
- Spring Boot: 시큐리티(Security) – 4 – 로그인 폼을 거치지 않고 컨트롤러에서 로그인
- Spring Boot: 시큐리티(Security) – 5 – 권한별 접근 가능한 페이지를 데이터베이스에 설정하기 (동적 설정)
- Spring Boot Security OAuth2: 커스텀 로그인 페이지 구현
5개의 댓글
스프링초절정꽃미남개발군단 · 2021년 1월 20일 11:18 오후
본문 중에 loginSuccessUrl 라고 설명해놨는데 그런거 없단다.
defaultSuccessUrl 나 successForwardUrl 겠지.
수정좀 하거라
글좋으니까
yoonbumtae (BGSMM) · 2021년 1월 21일 7:06 오후
알았다.
스프링초절정꽃미남개발군단 · 2021년 2월 4일 6:02 오후
아주 고오맙다아
참고 링크도 아주 잘보았다!
꿈나무 · 2021년 9월 7일 1:18 오후
안녕하세요, 시큐리티 공부하는데 도움이 많이 되었습니다.
한가지 궁금한게 있는데 /login에 post방식은 controller에 따로 추가한 부분이 없는 것 같은데
어떻게 동작하여 로그인이 되는 것인지 궁금합니다.
yoonbumtae (BGSMM) · 2021년 9월 7일 4:35 오후
스프링 시큐리티에서 자동적으로 get, post 별 작업을 구분해주는 것 같습니다. 똑같은 주소를 get으로 요청하면 로그인 페이지를 보여주고 post로 요청하면 로그인 작업을 처리하는 식입니다.
https://docs.spring.io/spring-security/site/docs/4.1.3.RELEASE/guides/html5/form-javaconfig.html