From 44daa3058b7e1e18b5bd04ff37b6058fd026fc0e Mon Sep 17 00:00:00 2001 From: geonhos Date: Mon, 20 May 2024 14:15:59 +0900 Subject: [PATCH] =?UTF-8?q?admin:=20custom=20=EB=A9=94=EB=89=B4=20?= =?UTF-8?q?=EC=9D=B8=EA=B0=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../poc/admin/security/SecurityConfig.java | 13 ++++++-- .../security/SecurityFilterConstants.java | 5 ---- .../CustomAccessDeniedHandler.java | 18 +++++++++++ .../CustomAuthorizationManager.java | 28 +++++++++++++++++ .../service/AuthorizationService.java | 30 +++++++++++++++++++ 5 files changed, 87 insertions(+), 7 deletions(-) delete mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityFilterConstants.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/CustomAccessDeniedHandler.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/CustomAuthorizationManager.java create mode 100644 poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/service/AuthorizationService.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 378e53d..71e9d4a 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 @@ -4,6 +4,9 @@ import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationEntryPo import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationFilter; import com.bpgroup.poc.admin.security.authentication.CustomAuthenticationProvider; import com.bpgroup.poc.admin.security.authentication.service.LoginService; +import com.bpgroup.poc.admin.security.authorization.CustomAccessDeniedHandler; +import com.bpgroup.poc.admin.security.authorization.CustomAuthorizationManager; +import com.bpgroup.poc.admin.security.authorization.service.AuthorizationService; import com.bpgroup.poc.admin.security.jwt.JwtTokenConstants; import com.bpgroup.poc.admin.security.jwt.JwtTokenValidateFilter; import lombok.RequiredArgsConstructor; @@ -35,6 +38,9 @@ public class SecurityConfig { private final LoginService loginService; + private final AuthorizationService authorizationService; + + @Bean SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { @@ -48,12 +54,14 @@ public class SecurityConfig { .cacheControl(cache -> cache.disable()) //ERR_CACHE_MISS ); - // 인증 설정 + // 인가 설정 http.authorizeHttpRequests(c -> c .requestMatchers("/css/**", "/images/**", "/js/**", "/font/**", "/favicon.ico").permitAll() .requestMatchers("/common/modal/**").permitAll() .requestMatchers(LOGIN_PATH, LOGOUT_PATH, ERROR_PATH).permitAll() - .anyRequest().authenticated()); + .anyRequest() + .access(new CustomAuthorizationManager(authorizationService)) + ); http.formLogin(AbstractHttpConfigurer::disable); // Form 로그인이 아닌 Json 로그인으로 분리 http.addFilterBefore(authenticationGenerateFilter(), UsernamePasswordAuthenticationFilter.class); // 로그인 관련 Filter 설정 @@ -67,6 +75,7 @@ public class SecurityConfig { http.exceptionHandling(c -> { c.authenticationEntryPoint(new CustomAuthenticationEntryPoint()); // Authentication 실패 처리 + c.accessDeniedHandler(new CustomAccessDeniedHandler()); // Authorization 실패 처리 }); http.logout(c -> c diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityFilterConstants.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityFilterConstants.java deleted file mode 100644 index 00e0beb..0000000 --- a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/SecurityFilterConstants.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.bpgroup.poc.admin.security; - -public class SecurityFilterConstants { - public static final String[] EXCLUDE_FILTER_STARTS_WITH_URI = {"/login", "/logout", "/error", "/css", "/js", "/images", "/favicon.ico", "/common/modal", "/font"}; -} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/CustomAccessDeniedHandler.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/CustomAccessDeniedHandler.java new file mode 100644 index 0000000..2907ed3 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/CustomAccessDeniedHandler.java @@ -0,0 +1,18 @@ +package com.bpgroup.poc.admin.security.authorization; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; + +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +public class CustomAccessDeniedHandler implements AccessDeniedHandler { + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { + response.sendRedirect("/error?error=" + URLEncoder.encode("메뉴에 접근할 수 있는 권한이 없습니다.", StandardCharsets.UTF_8)); + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/CustomAuthorizationManager.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/CustomAuthorizationManager.java new file mode 100644 index 0000000..41a5ace --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/CustomAuthorizationManager.java @@ -0,0 +1,28 @@ +package com.bpgroup.poc.admin.security.authorization; + +import com.bpgroup.poc.admin.security.authorization.service.AuthorizationService; +import lombok.RequiredArgsConstructor; +import org.springframework.security.authorization.AuthorizationDecision; +import org.springframework.security.authorization.AuthorizationManager; +import org.springframework.security.core.Authentication; +import org.springframework.security.web.access.intercept.RequestAuthorizationContext; + +import java.util.function.Supplier; + +@RequiredArgsConstructor +public class CustomAuthorizationManager implements AuthorizationManager { + + private final AuthorizationService authorizationService; + + @Override + public AuthorizationDecision check(Supplier authentication, RequestAuthorizationContext context) { + Authentication auth = (Authentication) authentication.get(); + + String userName = (String) auth.getPrincipal(); + String requestUri = context.getRequest().getRequestURI(); + + boolean hasAuthorization = authorizationService.isAuthorized(userName, requestUri); + + return new AuthorizationDecision(hasAuthorization); + } +} diff --git a/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/service/AuthorizationService.java b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/service/AuthorizationService.java new file mode 100644 index 0000000..115a585 --- /dev/null +++ b/poc/admin/src/main/java/com/bpgroup/poc/admin/security/authorization/service/AuthorizationService.java @@ -0,0 +1,30 @@ +package com.bpgroup.poc.admin.security.authorization.service; + +import com.bpgroup.poc.admin.domain.base.admin.entity.Admin; +import com.bpgroup.poc.admin.domain.base.admin.entity.AdminRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +@Slf4j +@Service +@RequiredArgsConstructor +@Transactional +public class AuthorizationService { + + private final AdminRepository adminRepository; + + public boolean isAuthorized(String username, String requestUri) { + Optional findAdmin = adminRepository.findByLoginId(username); + if (findAdmin.isEmpty()) { + return false; + } + + Admin admin = findAdmin.get(); + return admin.getAdminRole().getRole().getRoleMenus().stream() + .anyMatch(roleMenu -> roleMenu.getMenu().getUri().equals(requestUri)); + } +}