From b81ab51a117a1137c8a246c7e98e33b416906702 Mon Sep 17 00:00:00 2001 From: geonhos Date: Mon, 13 May 2024 15:21:49 +0900 Subject: [PATCH] =?UTF-8?q?admin:=20form=20=EA=B8=B0=EB=B0=98=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20->=20json=20http=20=EA=B8=B0=EB=B0=98=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../poc/admin/security/SecurityConfig.java | 52 ++++++++------ .../admin/security/SecurityEncryptConfig.java | 20 ++++++ .../authentication/AuthenticationDetail.java | 1 - .../AuthenticationFailReason.java | 24 ------- .../CustomAuthenticationFailureHandler.java | 36 ++++++++++ .../CustomAuthenticationFilter.java | 67 +++++++++++++++++++ .../CustomAuthenticationProvider.java | 17 ++--- .../CustomAuthenticationSuccessHandler.java | 35 ++++++++++ .../security/authentication/LoginRequest.java | 12 ++++ .../authentication/LoginResponse.java | 29 ++++++++ .../authentication}/LoginResult.java | 2 +- .../authentication}/LoginService.java | 26 +++---- .../AdministratorNotFoundException.java | 2 +- .../AuthenticationFailException.java | 2 +- .../exception/AuthenticationFailReason.java | 27 ++++++++ .../exception/DoNotHaveAnyMenuException.java | 2 +- .../exception/InvalidPasswordException.java | 2 +- .../poc/admin/values/AdministratorMenu.java | 4 -- .../poc/admin/web/login/LoginController.java | 20 +----- .../main/resources/templates/login/login.html | 15 +++++ 20 files changed, 299 insertions(+), 96 deletions(-) create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityEncryptConfig.java delete mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationFailReason.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationFailureHandler.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationFilter.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationSuccessHandler.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginRequest.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginResponse.java rename poc/admin/src/main/java/com/bpgroup/poc/admin/{app/login => security/authentication}/LoginResult.java (96%) rename poc/admin/src/main/java/com/bpgroup/poc/admin/{app/login => security/authentication}/LoginService.java (66%) rename poc/admin/src/main/java/com/bpgroup/poc/admin/{app/login => security/authentication}/exception/AdministratorNotFoundException.java (70%) rename poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/{ => exception}/AuthenticationFailException.java (85%) create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AuthenticationFailReason.java rename poc/admin/src/main/java/com/bpgroup/poc/admin/{app/login => security/authentication}/exception/DoNotHaveAnyMenuException.java (65%) rename poc/admin/src/main/java/com/bpgroup/poc/admin/{app/login => security/authentication}/exception/InvalidPasswordException.java (69%) delete mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/values/AdministratorMenu.java diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityConfig.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityConfig.java index 9733e23..74ec9a9 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityConfig.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityConfig.java @@ -1,18 +1,24 @@ package com.bpgroup.poc.admin.security; -import com.bpgroup.poc.admin.common.FormatHelper; -import com.bpgroup.poc.admin.security.authentication.AuthenticationFailException; +import com.bpgroup.poc.admin.security.authentication.LoginService; +import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationFilter; +import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationProvider; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.ProviderManager; import org.springframework.security.config.Customizer; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.header.writers.XXssProtectionHeaderWriter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import java.util.Objects; +import java.util.ArrayList; +import java.util.List; @Configuration @RequiredArgsConstructor @@ -22,6 +28,8 @@ public class SecurityConfig { private static final String LOGOUT_PATH = "/logout"; private static final String ERROR_PATH = "/error"; + private final LoginService loginService; + @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { // 보안 기본 설정 @@ -39,19 +47,8 @@ public class SecurityConfig { .requestMatchers(LOGIN_PATH, LOGOUT_PATH, ERROR_PATH).permitAll() .anyRequest().authenticated()); - http.formLogin(c -> c - .loginPage(LOGIN_PATH) - .loginProcessingUrl(LOGIN_PATH) - .usernameParameter("loginId") - .passwordParameter("password") - .defaultSuccessUrl("/main") - .failureHandler((req, res, ex) -> { - if (Objects.requireNonNull(ex) instanceof AuthenticationFailException authenticationFailException) { - res.sendRedirect(FormatHelper.format(LOGIN_PATH + "?error={}", authenticationFailException.getReason())); - } else { - res.sendRedirect(ERROR_PATH); - } - })); + http.formLogin(AbstractHttpConfigurer::disable); // Form 로그인이 아닌 Json 로그인으로 분리 + http.addFilterBefore(authenticationGenerateFilter(), UsernamePasswordAuthenticationFilter.class); // 로그인 관련 Filter 설정 http.logout(c -> c .logoutRequestMatcher(new AntPathRequestMatcher(LOGOUT_PATH, "GET")) @@ -61,12 +58,23 @@ public class SecurityConfig { return http.build(); } - /** - * Bcrypt Version, Bcrypt Strength, Salt String 설정은 생성자를 이용하여 설정 가능 - */ @Bean - public BCryptPasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); + public CustomAuthenticationProvider customAuthenticationProvider() { + return new CustomAuthenticationProvider(loginService); + } + + @Bean + public AuthenticationManager authenticationManager() { + List providers = new ArrayList<>(); + providers.add(customAuthenticationProvider()); + return new ProviderManager(providers); + } + + @Bean + public CustomAuthenticationFilter authenticationGenerateFilter() { + CustomAuthenticationFilter filter = new CustomAuthenticationFilter(); + filter.setAuthenticationManager(authenticationManager()); + return filter; } } diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityEncryptConfig.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityEncryptConfig.java new file mode 100644 index 0000000..31fd7c6 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityEncryptConfig.java @@ -0,0 +1,20 @@ +package com.bpgroup.poc.admin.security; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +/** + * SecurityConfig 에 있을 경우 Service 에 주입 시 순환 참조가 발생하여 별로 파일로 분리 + */ +@Configuration +public class SecurityEncryptConfig { + /** + * Bcrypt Version, Bcrypt Strength, Salt String 설정은 생성자를 이용하여 설정 가능 + */ + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } + +} \ No newline at end of file diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationDetail.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationDetail.java index d702f7e..674b30d 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationDetail.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationDetail.java @@ -1,6 +1,5 @@ package com.bpgroup.poc.admin.security.authentication; -import com.bpgroup.poc.admin.app.login.LoginResult; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationFailReason.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationFailReason.java deleted file mode 100644 index 3240105..0000000 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationFailReason.java +++ /dev/null @@ -1,24 +0,0 @@ -package com.bpgroup.poc.admin.security.authentication; - -import com.bpgroup.poc.admin.app.login.exception.AdministratorNotFoundException; -import com.bpgroup.poc.admin.app.login.exception.DoNotHaveAnyMenuException; -import com.bpgroup.poc.admin.app.login.exception.InvalidPasswordException; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public enum AuthenticationFailReason { - WRONG_LOGIN_ID, - WRONG_PASSWORD, - HAVE_NO_MENU, - INTERNAL_ERROR; - - public static AuthenticationFailReason from(Exception e) { - if (e instanceof AdministratorNotFoundException || e instanceof InvalidPasswordException) { - return WRONG_LOGIN_ID; - } else if (e instanceof DoNotHaveAnyMenuException) { - return HAVE_NO_MENU; - } else { - return INTERNAL_ERROR; - } - } -} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationFailureHandler.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationFailureHandler.java new file mode 100644 index 0000000..1a72347 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationFailureHandler.java @@ -0,0 +1,36 @@ +package com.bpgroup.poc.admin.security.authentication; + +import com.bpgroup.poc.admin.security.authentication.exception.AuthenticationFailException; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.MediaType; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AuthenticationFailureHandler; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler { + @Override + public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + String failMessage = "시스템 오류가 발생했습니다."; + + if (Objects.requireNonNull(exception) instanceof AuthenticationFailException authenticationFailException) { + failMessage = authenticationFailException.getReason().getMessage(); + } + + String jsonResponse = new ObjectMapper().writeValueAsString( + LoginResponse.fail( + "9999", + failMessage + ) + ); + response.getWriter().write(jsonResponse); + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationFilter.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationFilter.java new file mode 100644 index 0000000..b300331 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationFilter.java @@ -0,0 +1,67 @@ +package com.bpgroup.poc.admin.security.authentication; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.authentication.AuthenticationServiceException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.util.StreamUtils; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter { + private static final String DEFAULT_LOGIN_REQUEST_URL = "/login"; + private static final String HTTP_METHOD = "POST"; + private static final String CONTENT_TYPE = "application/json"; + private boolean postOnly = true; + + public CustomAuthenticationFilter() { + super(new AntPathRequestMatcher(DEFAULT_LOGIN_REQUEST_URL, HTTP_METHOD)); // 위에서 설정한 /oauth2/login/* 의 요청에, GET으로 온 요청을 처리하기 위해 설정한다. + setAuthenticationSuccessHandler(new CustomAuthenticationSuccessHandler()); + setAuthenticationFailureHandler(new CustomAuthenticationFailureHandler()); + } + + @Override + public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { + // 요청에 대한 유효성 검사 + isValidated(request); + + LoginRequest loginRequest = new ObjectMapper().readValue( + StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8), + LoginRequest.class + ); + + String username = loginRequest.getUsername(); + String password = loginRequest.getPassword(); + + if (username == null || password == null) { + throw new AuthenticationServiceException("DATA IS MISS"); + } + + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password); + setDetails(request, authenticationToken); + + return this.getAuthenticationManager().authenticate(authenticationToken); + } + + private void isValidated(HttpServletRequest request) { + if (this.postOnly && !request.getMethod().equals(HTTP_METHOD)) { + throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); + } + + if (request.getContentType() == null || !request.getContentType().equals(CONTENT_TYPE)) { + throw new AuthenticationServiceException("Authentication Content-Type not supported: " + request.getContentType()); + } + } + + protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) { + authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request)); + } + +} \ No newline at end of file diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationProvider.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationProvider.java index 562a71c..3be661e 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationProvider.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationProvider.java @@ -1,27 +1,28 @@ package com.bpgroup.poc.admin.security.authentication; -import com.bpgroup.poc.admin.app.login.LoginResult; -import com.bpgroup.poc.admin.app.login.LoginService; +import com.bpgroup.poc.admin.security.authentication.exception.AuthenticationFailException; +import com.bpgroup.poc.admin.security.authentication.exception.AuthenticationFailReason; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.AuthenticationProvider; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; -import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; -@Component @RequiredArgsConstructor public class CustomAuthenticationProvider implements AuthenticationProvider { private final LoginService loginService; + @Transactional @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { - String loginId = (String) authentication.getPrincipal(); - String password = (String) authentication.getCredentials(); - try { - LoginResult loginResult = loginService.login(loginId, password); + String username = (String) authentication.getPrincipal(); + String password = (String) authentication.getCredentials(); + + LoginResult loginResult = loginService.login(username, password); + return buildAuthenticationToken(loginResult); } catch (Exception e) { throw new AuthenticationFailException("로그인에 실패하였습니다.", AuthenticationFailReason.from(e)); diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationSuccessHandler.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationSuccessHandler.java new file mode 100644 index 0000000..2be1a79 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/CustomAuthenticationSuccessHandler.java @@ -0,0 +1,35 @@ +package com.bpgroup.poc.admin.security.authentication; + +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.http.MediaType; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler { + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException { + AuthenticationSuccessHandler.super.onAuthenticationSuccess(request, response, chain, authentication); + } + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { + response.setStatus(HttpServletResponse.SC_OK); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + + String jsonResponse = new ObjectMapper().writeValueAsString( + LoginResponse.success( + "token" + ) + ); + + response.getWriter().write(jsonResponse); + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginRequest.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginRequest.java new file mode 100644 index 0000000..509f245 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginRequest.java @@ -0,0 +1,12 @@ +package com.bpgroup.poc.admin.security.authentication; + +import lombok.Data; + +/** + * 로그인 요청 Request + */ +@Data +public class LoginRequest { + private String username; + private String password; +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginResponse.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginResponse.java new file mode 100644 index 0000000..87c1129 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginResponse.java @@ -0,0 +1,29 @@ +package com.bpgroup.poc.admin.security.authentication; + +import lombok.Getter; +import lombok.ToString; + +@Getter +@ToString +public class LoginResponse { + + private String resultCode; + private String resultMessage; + private String token; + + public static LoginResponse success(String token) { + LoginResponse response = new LoginResponse(); + response.resultCode = "0000"; + response.resultMessage = "Success"; + response.token = token; + return response; + } + + public static LoginResponse fail(String resultCode, String resultMessage) { + LoginResponse response = new LoginResponse(); + response.resultCode = resultCode; + response.resultMessage = resultMessage; + return response; + } + +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/LoginResult.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginResult.java similarity index 96% rename from poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/LoginResult.java rename to poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginResult.java index 5195fbd..d375ac9 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/LoginResult.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginResult.java @@ -1,4 +1,4 @@ -package com.bpgroup.poc.admin.app.login; +package com.bpgroup.poc.admin.security.authentication; import lombok.EqualsAndHashCode; import lombok.Getter; diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/LoginService.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginService.java similarity index 66% rename from poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/LoginService.java rename to poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginService.java index 35535b0..5fc8db3 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/LoginService.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/LoginService.java @@ -1,8 +1,8 @@ -package com.bpgroup.poc.admin.app.login; +package com.bpgroup.poc.admin.security.authentication; -import com.bpgroup.poc.admin.app.login.exception.AdministratorNotFoundException; -import com.bpgroup.poc.admin.app.login.exception.DoNotHaveAnyMenuException; -import com.bpgroup.poc.admin.app.login.exception.InvalidPasswordException; +import com.bpgroup.poc.admin.security.authentication.exception.AdministratorNotFoundException; +import com.bpgroup.poc.admin.security.authentication.exception.DoNotHaveAnyMenuException; +import com.bpgroup.poc.admin.security.authentication.exception.InvalidPasswordException; import com.bpgroup.poc.admin.domain.admin.entity.Administrator; import com.bpgroup.poc.admin.domain.admin.entity.AdministratorRepository; import lombok.RequiredArgsConstructor; @@ -17,21 +17,20 @@ import java.util.stream.Collectors; @Service @RequiredArgsConstructor -@Transactional public class LoginService { - private final AdministratorRepository loginRepository; + private final AdministratorRepository administratorRepository; private final PasswordEncoder passwordEncoder; - public LoginResult login(String loginId, String pwd) throws AdministratorNotFoundException, InvalidPasswordException, DoNotHaveAnyMenuException { - - Optional administrator = loginRepository.findByLoginId(loginId); + @Transactional + public LoginResult login(String username, String password) throws AdministratorNotFoundException, InvalidPasswordException, DoNotHaveAnyMenuException { + Optional administrator = administratorRepository.findByLoginId(username); if (administrator.isEmpty()) { - throw new AdministratorNotFoundException(loginId); + throw new AdministratorNotFoundException(username); } - if (!passwordEncoder.matches(pwd, administrator.get().getPassword())) { - throw new InvalidPasswordException(loginId); + if (!passwordEncoder.matches(password, administrator.get().getPassword())) { + throw new InvalidPasswordException(username); } return LoginResult.of( @@ -43,7 +42,7 @@ public class LoginService { ); } - private static LinkedHashSet getMenus(Administrator administrator) throws DoNotHaveAnyMenuException { + private LinkedHashSet getMenus(Administrator administrator) throws DoNotHaveAnyMenuException { try { return administrator.getAdministratorRole().getRole().getRoleMenus().stream() .map(roleMenu -> LoginResult.MenuInfo.of( @@ -65,4 +64,5 @@ public class LoginService { } } + } diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/exception/AdministratorNotFoundException.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AdministratorNotFoundException.java similarity index 70% rename from poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/exception/AdministratorNotFoundException.java rename to poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AdministratorNotFoundException.java index 2a5a905..3835a87 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/exception/AdministratorNotFoundException.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AdministratorNotFoundException.java @@ -1,4 +1,4 @@ -package com.bpgroup.poc.admin.app.login.exception; +package com.bpgroup.poc.admin.security.authentication.exception; public class AdministratorNotFoundException extends Exception { public AdministratorNotFoundException(String message) { diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationFailException.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AuthenticationFailException.java similarity index 85% rename from poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationFailException.java rename to poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AuthenticationFailException.java index d6f5e36..55bb1aa 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/AuthenticationFailException.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AuthenticationFailException.java @@ -1,4 +1,4 @@ -package com.bpgroup.poc.admin.security.authentication; +package com.bpgroup.poc.admin.security.authentication.exception; import lombok.Getter; import org.springframework.security.core.AuthenticationException; diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AuthenticationFailReason.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AuthenticationFailReason.java new file mode 100644 index 0000000..eece553 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/AuthenticationFailReason.java @@ -0,0 +1,27 @@ +package com.bpgroup.poc.admin.security.authentication.exception; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum AuthenticationFailReason { + WRONG_LOGIN_ID("아이디 및 패스워드를 확인하세요."), + WRONG_PASSWORD("아이디 및 패스워드를 확인하세요."), + HAVE_NO_MENU("등록된 메뉴 권한이 없습니다. \n메뉴 등록 후 사용하시기 바랍니다."), + INTERNAL_ERROR("서버 내부 오류가 발생했습니다."); + + private final String message; + + public static AuthenticationFailReason from(Exception e) { + if (e instanceof AdministratorNotFoundException) { + return WRONG_LOGIN_ID; + } else if (e instanceof InvalidPasswordException) { + return WRONG_PASSWORD; + } else if (e instanceof DoNotHaveAnyMenuException) { + return HAVE_NO_MENU; + } else { + return INTERNAL_ERROR; + } + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/exception/DoNotHaveAnyMenuException.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/DoNotHaveAnyMenuException.java similarity index 65% rename from poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/exception/DoNotHaveAnyMenuException.java rename to poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/DoNotHaveAnyMenuException.java index 82690a5..5baf9fe 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/exception/DoNotHaveAnyMenuException.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/DoNotHaveAnyMenuException.java @@ -1,4 +1,4 @@ -package com.bpgroup.poc.admin.app.login.exception; +package com.bpgroup.poc.admin.security.authentication.exception; public class DoNotHaveAnyMenuException extends Exception { public DoNotHaveAnyMenuException() { diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/exception/InvalidPasswordException.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/InvalidPasswordException.java similarity index 69% rename from poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/exception/InvalidPasswordException.java rename to poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/InvalidPasswordException.java index 691e081..c00c208 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/app/login/exception/InvalidPasswordException.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authentication/exception/InvalidPasswordException.java @@ -1,4 +1,4 @@ -package com.bpgroup.poc.admin.app.login.exception; +package com.bpgroup.poc.admin.security.authentication.exception; public class InvalidPasswordException extends Exception { public InvalidPasswordException(String message) { diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/values/AdministratorMenu.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/values/AdministratorMenu.java deleted file mode 100644 index f485fd3..0000000 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/values/AdministratorMenu.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.bpgroup.poc.admin.values; - -public class AdministratorMenu { -} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/web/login/LoginController.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/web/login/LoginController.java index e7761e5..1a7ca47 100644 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/web/login/LoginController.java +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/web/login/LoginController.java @@ -1,34 +1,16 @@ package com.bpgroup.poc.admin.web.login; -import com.bpgroup.poc.admin.security.authentication.AuthenticationFailReason; import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; @Controller @RequestMapping("/login") public class LoginController { @GetMapping - public String loginPage( - @RequestParam(required = false) AuthenticationFailReason error, - Model model - ) { - if (error != null) { - model.addAttribute("errorMessage", getMessage(error)); - } - + public String loginPage() { return "login/login"; } - private String getMessage(AuthenticationFailReason error) { - return switch (error) { - case WRONG_LOGIN_ID, WRONG_PASSWORD -> "아이디 또는 비밀번호가 일치하지 않습니다."; - case HAVE_NO_MENU -> "등록된 메뉴가 없습니다.\n 메뉴 등록 후 이용해주세요."; - default -> "서버에 오류가 발생했습니다."; - }; - } - } diff --git a/poc/admin/src/main/resources/templates/login/login.html b/poc/admin/src/main/resources/templates/login/login.html index 19a06d3..ba538a4 100644 --- a/poc/admin/src/main/resources/templates/login/login.html +++ b/poc/admin/src/main/resources/templates/login/login.html @@ -11,6 +11,7 @@ + @@ -30,10 +31,24 @@

+