Spring Security을 이용하여 인증과 인가의 관련된 Handler를 다루어 보겠습니다.
AuthenticationSuccessHandler
을 상속 받아 사용하는 SimpleUrlAuthenticationSuccessHandler
를 이용하여 성공했을때 진입할 수 있는 페이지를 작성해봅니다.
@Component
public class CustomAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private RequestCache requestCache = new HttpSessionRequestCache();
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
setDefaultTargetUrl("/");
SavedRequest savedRequest = requestCache.getRequest(request, response);
if(savedRequest != null){
String targetUrl = savedRequest.getRedirectUrl();
redirectStrategy.sendRedirect(request, response, targetUrl);
}else {
redirectStrategy.sendRedirect(request, response, getDefaultTargetUrl());
}
}
}
savedRequest
는 인증이 발생하기 전 페이지를 저장해두었다가, 로그인 이동 후 인증이 완료되면 다시 보여줄 화면을 말합니다. 예를 들면 로그인 안 한 상태에서 마이페이지를 클릭 후 인증을 거치면, 마이페이지 화면을 출력하게 되는 것입니다.
setDefaultTargetUrl
을 통해서 아무런 save가 없다면, 홈화면으로 이동하게 해줍니다.
마찬가지로 부모가되는 AuthenticationFailureHandler
를 상속받은 SimpleUrlAuthenticationFailureHandler
로 시작하게 됩니다.
@Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
String errorMessage = "Invalid Username or Password";
if(exception instanceof BadCredentialsException) errorMessage = "Invalid Username or Password";
else if(exception instanceof InsufficientAuthenticationException) errorMessage = "Invalid Secret Key";
setDefaultFailureUrl("/login?error=true&exception=" + errorMessage);
super.onAuthenticationFailure(request, response, exception);
}
}
이 외에 request
와 response
를 이용하여 셋팅하셔도 됩니다.
//query parameter로 넘겨서 처리하는거 말고 아래 방식으로 처리해도 됩니다.
request.setAttribute();
response.setStatus();
AccessDenied는 인가처리를 위한 작업을 하기위해 작성하는 겁니다.
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
private String errorPage;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
String deniedUrl = errorPage + "?exception=" + e.getMessage();
response.sendRedirect(deniedUrl);
}
// 페이지를 따로 나눌게 아니면 setter말고 하드코딩하셔도 됩니다.
public void setErrorPage(String errorPage){
this.errorPage = errorPage;
}
}
인증? 인가?
인증 : 로그인을 하는 행위, 회원(Authenticate), 비회원(Anonymous)
인가 : 접근권한을 정하는 행위(Authorization), 회원설정페이지, 관리자페이지 등등
해당페이지의 컨트롤러를 작성해줍니다. 방식은 어떻게 리턴할꺼냐에 따라 달라질 수 있겠습니다.
본인이 만들어놓은 Handler
에 맞게 작성하시면 됩니다.
@GetMapping("/login")
public String login(
@RequestParam(value="error", required = false) String error
, @RequestParam(value="exception", required = false) String exception
, Model model){
model.addAttribute("error", error);
model.addAttribute("exception", exception);
return "user/login/login";
}
@GetMapping("/denied")
public String accessDenied(@RequestParam(value = "exception", required = false) String exception, Model model){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Account account = (Account) authentication.getPrincipal();
model.addAttribute("username", account.getUsername());
model.addAttribute("exception", exception);
return "user/login/denied";
}
configure
파일도 설정에 맞게 추가해주시면 됩니다.
@Autowired
private AuthenticationSuccessHandler authenticationSuccessHandler;
@Autowired
private AuthenticationFailureHandler authenticationFailureHandler;
//중략...
@Override
protected void configure(final HttpSecurity http) throws Exception {
http
//.antMathers()중략...
.successHandler(authenticationSuccessHandler)
.failureHandler(authenticationFailureHandler)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler())
;
;
}
@Bean
public AccessDeniedHandler accessDeniedHandler() {
CustomAccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler();
accessDeniedHandler.setErrorPage("/denied");
return accessDeniedHandler ;
}