diff --git a/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationFailureHandler.java b/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationFailureHandler.java new file mode 100644 index 0000000..8068629 --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationFailureHandler.java @@ -0,0 +1,51 @@ +package com.eactive.httpmockserver.config; + +import com.eactive.httpmockserver.common.entity.EnabledStatus; +import com.eactive.httpmockserver.login.controller.LoginController; +import com.eactive.httpmockserver.user.entity.StaffUser; +import com.eactive.httpmockserver.user.entity.User; +import com.eactive.httpmockserver.user.repository.StaffUserRepository; +import com.eactive.httpmockserver.user.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + +@Service +@Transactional +public class PortalAuthenticationFailureHandler implements AuthenticationFailureHandler { + + @Autowired + UserService userService; + + @Autowired + StaffUserRepository staffUserRepository; + + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException { + + String username = request.getParameter("id"); + + User user = userService.findByUserId(username); + user.setLockCnt(user.getLockCnt() + 1); + if (user.getLockCnt() >= 5) { + user.setLockAt(EnabledStatus.Y); + } + + staffUserRepository.save((StaffUser) user); + + request.getSession().setAttribute(LoginController.LOGIN_MESSAGE, exception.getMessage()); + + String contextPath = request.getContextPath(); + + response.sendRedirect(contextPath + "/login"); + } +} diff --git a/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationManager.java b/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationManager.java index 2747f42..2ba08ab 100644 --- a/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationManager.java +++ b/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationManager.java @@ -1,6 +1,7 @@ package com.eactive.httpmockserver.config; +import com.eactive.httpmockserver.common.util.EncryptionUtil; import com.eactive.httpmockserver.user.entity.User; import com.eactive.httpmockserver.user.service.UserService; import org.springframework.beans.factory.annotation.Autowired; @@ -9,21 +10,29 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional public class PortalAuthenticationManager implements AuthenticationManager { @Autowired private UserService userService; + @Autowired + private EncryptionUtil encryptionUtil; + + @Override - @Transactional public Authentication authenticate(Authentication authentication) throws AuthenticationException { UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; String username = token.getName(); String password = token.getCredentials().toString(); UserDetails user = userService.loadUserByUsername(username); + String encryptPassword = encryptionUtil.encryptPassword(password, username); if (!user.isEnabled()) { throw new DisabledException("계정이 " + ((User) user).getStatus().getDescription() + "상태입니다. 관리자에게 문의하세요."); @@ -33,7 +42,7 @@ public class PortalAuthenticationManager implements AuthenticationManager { throw new LockedException("계정이 잠겨있습니다. 관리자에게 문의하세요."); } - if (user.getPassword().equals(password)) { + if (user.getPassword().equals(encryptPassword)) { UsernamePasswordAuthenticationToken authorityToken = new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities()); authorityToken.setDetails(user); diff --git a/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationSuccessHandler.java b/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationSuccessHandler.java new file mode 100644 index 0000000..bae39fe --- /dev/null +++ b/src/main/java/com/eactive/httpmockserver/config/PortalAuthenticationSuccessHandler.java @@ -0,0 +1,43 @@ +package com.eactive.httpmockserver.config; + +import com.eactive.httpmockserver.user.entity.User; +import com.eactive.httpmockserver.user.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; + + +@Service +@Transactional +public class PortalAuthenticationSuccessHandler implements AuthenticationSuccessHandler { + + @Autowired + UserService userService; + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { + String username = request.getParameter("id"); + UserDetails user = userService.loadUserByUsername(username); + ((User) user).setLockCnt(0); + userService.updateUser((User) user); + + String contextPath = request.getContextPath(); + response.sendRedirect(contextPath + "/"); + } + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException { + AuthenticationSuccessHandler.super.onAuthenticationSuccess(request, response, chain, authentication); + } +} + + diff --git a/src/main/java/com/eactive/httpmockserver/config/PortalConfigSecurity.java b/src/main/java/com/eactive/httpmockserver/config/PortalConfigSecurity.java index 3839e42..9bb3c74 100644 --- a/src/main/java/com/eactive/httpmockserver/config/PortalConfigSecurity.java +++ b/src/main/java/com/eactive/httpmockserver/config/PortalConfigSecurity.java @@ -2,6 +2,7 @@ package com.eactive.httpmockserver.config; import com.navercorp.lucy.security.xss.servletfilter.XssEscapeServletFilter; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -15,27 +16,38 @@ import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @EnableWebSecurity public class PortalConfigSecurity extends WebSecurityConfigurerAdapter { + @Bean + public FilterRegistrationBean xssFilterRegistrationBean() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + XssEscapeServletFilter xssEscapeServletFilter = new XssEscapeServletFilter(); + registrationBean.setFilter(xssEscapeServletFilter); + registrationBean.setOrder(Integer.MIN_VALUE + 1); + registrationBean.addUrlPatterns("/*"); + return registrationBean; + } -// @Bean -// public FilterRegistrationBean xssFilterRegistrationBean() { -// FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); -// XssEscapeServletFilter xssEscapeServletFilter = new XssEscapeServletFilter(); -// registrationBean.setFilter(xssEscapeServletFilter); -// registrationBean.setOrder(Integer.MIN_VALUE + 1); -// registrationBean.addUrlPatterns("/*"); -// return registrationBean; -// } + @Autowired + public PortalAuthenticationFailureHandler authenticationFailureHandler; + + @Autowired + public PortalAuthenticationSuccessHandler authenticationSuccessHandler; @Override protected void configure(HttpSecurity http) throws Exception { - http - .httpBasic() - .disable(); - http.headers().frameOptions().disable();//spring security 와 h2-console 같이 사용. - http.authorizeRequests() // 권한요청 처리 설정 메서드 + http + .formLogin() + .loginPage("/login") + .usernameParameter("id") + .passwordParameter("password") + .loginProcessingUrl("/actionLogin.do") + .successHandler(authenticationSuccessHandler) + .failureHandler(authenticationFailureHandler) + .and() + .logout().logoutUrl("/actionLogout.do").logoutSuccessUrl("/") + .and().authorizeRequests() // 권한요청 처리 설정 메서드 .antMatchers("/h2-console/**").permitAll() // 누구나 h2-console 접속 허용 .and() .csrf() @@ -44,10 +56,13 @@ public class PortalConfigSecurity extends WebSecurityConfigurerAdapter { } + @Autowired + PortalAuthenticationManager portalAuthenticationManager; + @Override @Bean public PortalAuthenticationManager authenticationManager() { - return new PortalAuthenticationManager(); + return portalAuthenticationManager; } } diff --git a/src/main/java/com/eactive/httpmockserver/login/controller/LoginController.java b/src/main/java/com/eactive/httpmockserver/login/controller/LoginController.java index 3f8d591..a925ed3 100644 --- a/src/main/java/com/eactive/httpmockserver/login/controller/LoginController.java +++ b/src/main/java/com/eactive/httpmockserver/login/controller/LoginController.java @@ -1,24 +1,16 @@ package com.eactive.httpmockserver.login.controller; -import com.eactive.httpmockserver.common.util.EncryptionUtil; -import com.eactive.httpmockserver.login.dto.LoginRequestDTO; -import com.eactive.httpmockserver.login.service.LoginService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.BadCredentialsException; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import com.eactive.httpmockserver.user.service.UserService; +import org.apache.commons.lang3.StringUtils; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; -import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -34,14 +26,12 @@ import java.util.Map; public class LoginController { public static final String LOGIN_MESSAGE = "loginMessage"; - @Resource(name = "loginService") - private LoginService loginService; - @Autowired - private AuthenticationManager authenticationManager; + private UserService userService; - @Autowired - private EncryptionUtil encryptionUtil; + public LoginController(UserService userService) { + this.userService = userService; + } /** * 로그인 화면으로 들어간다 @@ -49,36 +39,22 @@ public class LoginController { * @return 로그인 페이지 */ @GetMapping("/login") - public String loginUsrView(HttpServletRequest request, + public String loginUsrView(HttpSession session, ModelMap model) { - String message = request.getParameter(LOGIN_MESSAGE); - if (message != null) + if (!userService.isInitialized()) { + return "redirect:/admin_register_view.do"; + } + + String message = (String) session.getAttribute(LOGIN_MESSAGE); + if (StringUtils.isNotEmpty(message)){ model.addAttribute(LOGIN_MESSAGE, message); + } + session.setAttribute(LOGIN_MESSAGE, null); return "page/login"; } - @PostMapping(value = "/actionLogin.do") - public String actionLogin(@ModelAttribute("loginVO") LoginRequestDTO loginUser, - HttpSession session, - ModelMap model) { - try { - String encryptPassword = encryptionUtil.encryptPassword(loginUser.getPassword(), loginUser.getId()); - Authentication authentication = new UsernamePasswordAuthenticationToken(loginUser.getId(), encryptPassword); - authenticationManager.authenticate(authentication); - return "redirect:/"; - } catch (BadCredentialsException e) { - loginService.processIncorrectLogin(loginUser); - model.addAttribute(LOGIN_MESSAGE, e.getMessage()); - } catch (Exception e) { - model.addAttribute(LOGIN_MESSAGE, e.getMessage()); - } - - return "redirect:/login"; - } - - /** * 세션타임아웃 시간을 연장한다. * Cookie에 egovLatestServerTime, egovExpireSessionTime 기록하도록 한다. diff --git a/src/main/java/com/eactive/httpmockserver/user/service/UserService.java b/src/main/java/com/eactive/httpmockserver/user/service/UserService.java index 7e14ed7..d11af15 100644 --- a/src/main/java/com/eactive/httpmockserver/user/service/UserService.java +++ b/src/main/java/com/eactive/httpmockserver/user/service/UserService.java @@ -68,4 +68,8 @@ public class UserService implements UserDetailsService { public StaffUser findByEsntlId(String esntlId) { return staffUserRepository.findById(esntlId).orElseThrow(() -> new UserNotFoundException(USER_NOT_FOUND_MESSAGE)); } + + public boolean isInitialized(){ + return staffUserRepository.count() > 0; + } }