diff --git a/src/main/java/com/hanstack/linkedintool/config/SpringSecurity.java b/src/main/java/com/hanstack/linkedintool/config/SpringSecurity.java index a193590..c0ff0e2 100644 --- a/src/main/java/com/hanstack/linkedintool/config/SpringSecurity.java +++ b/src/main/java/com/hanstack/linkedintool/config/SpringSecurity.java @@ -12,6 +12,7 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; import org.springframework.security.web.authentication.logout.HeaderWriterLogoutHandler; import org.springframework.security.web.header.writers.ClearSiteDataHeaderWriter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; @@ -23,6 +24,8 @@ public class SpringSecurity { private UserDetailsService userDetailsService; + private AuthenticationSuccessHandler customAuthenticationSuccessHandler; + @Bean public static PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); @@ -36,18 +39,21 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .requestMatchers("/crx/**", "/css/**", "/img/**", "/js/**", "/vendor/**").permitAll() .requestMatchers("/register/**").permitAll() .requestMatchers("/forgot-password/**").permitAll() - .requestMatchers("/home").hasRole("ADMIN") + .requestMatchers("/home", "/").hasRole("ADMIN") + .requestMatchers("/selenium/**").hasRole("ADMIN") ).formLogin( form -> form .loginPage("/login") .loginProcessingUrl("/login") - .defaultSuccessUrl("/home", true) +// .defaultSuccessUrl("/home", true) + .successHandler(customAuthenticationSuccessHandler) .permitAll() ).logout( logout -> logout .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .addLogoutHandler(new HeaderWriterLogoutHandler(new ClearSiteDataHeaderWriter(ClearSiteDataHeaderWriter.Directive.ALL))) + .logoutSuccessUrl("/login") .permitAll() ); return http.build(); @@ -59,4 +65,5 @@ public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder()); } + } diff --git a/src/main/java/com/hanstack/linkedintool/controller/AuthController.java b/src/main/java/com/hanstack/linkedintool/controller/AuthController.java index 3a33116..e0e887e 100644 --- a/src/main/java/com/hanstack/linkedintool/controller/AuthController.java +++ b/src/main/java/com/hanstack/linkedintool/controller/AuthController.java @@ -6,6 +6,7 @@ import com.hanstack.linkedintool.enums.ToolbarEnum; import com.hanstack.linkedintool.model.User; import com.hanstack.linkedintool.service.UserService; +import com.hanstack.linkedintool.util.AuthUtil; import jakarta.servlet.http.HttpSession; import jakarta.validation.Valid; import lombok.AllArgsConstructor; @@ -22,6 +23,11 @@ public class AuthController { private UserService userService; + @GetMapping("/") + public String defaultHome() { + return "redirect:/home"; + } + @GetMapping("/home") public String home(Model model, HttpSession httpSession) { FilterDTO filterDTO = FilterDTO.builder() @@ -40,6 +46,9 @@ public String home(Model model, HttpSession httpSession) { @GetMapping("/login") public String loginForm() { + if (AuthUtil.isLogin()) { + return "redirect:/home"; + } return "layout/auth/login"; } diff --git a/src/main/java/com/hanstack/linkedintool/security/CustomAuthenticationSuccessHandler.java b/src/main/java/com/hanstack/linkedintool/security/CustomAuthenticationSuccessHandler.java new file mode 100644 index 0000000..42757db --- /dev/null +++ b/src/main/java/com/hanstack/linkedintool/security/CustomAuthenticationSuccessHandler.java @@ -0,0 +1,77 @@ +package com.hanstack.linkedintool.security; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.web.DefaultRedirectStrategy; +import org.springframework.security.web.RedirectStrategy; +import org.springframework.security.web.WebAttributes; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@NoArgsConstructor +@Component +public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler { + + private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy(); + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { + handle(request, response, authentication); + clearAuthenticationAttributes(request); + } + + protected void handle(final HttpServletRequest request, final HttpServletResponse response, final Authentication authentication) throws IOException { + final String targetUrl = determineTargetUrl(authentication); + + if (response.isCommitted()) { + log.debug("Response has already been committed. Unable to redirect to " + targetUrl); + return; + } + + redirectStrategy.sendRedirect(request, response, targetUrl); + } + + protected String determineTargetUrl(final Authentication authentication) { + + Map roleTargetUrlMap = new HashMap<>(); + roleTargetUrlMap.put("ROLE_USER", "/home"); + roleTargetUrlMap.put("ROLE_ADMIN", "/home"); + + final Collection authorities = authentication.getAuthorities(); + for (final GrantedAuthority grantedAuthority : authorities) { + + String authorityName = grantedAuthority.getAuthority(); + if (roleTargetUrlMap.containsKey(authorityName)) { + return roleTargetUrlMap.get(authorityName); + } + } + + throw new IllegalStateException(); + } + + /** + * Removes temporary authentication-related data which may have been stored in the session + * during the authentication process. + */ + protected final void clearAuthenticationAttributes(final HttpServletRequest request) { + final HttpSession session = request.getSession(false); + + if (session == null) { + return; + } + + session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION); + } +} diff --git a/src/main/java/com/hanstack/linkedintool/util/AuthUtil.java b/src/main/java/com/hanstack/linkedintool/util/AuthUtil.java new file mode 100644 index 0000000..1b02b21 --- /dev/null +++ b/src/main/java/com/hanstack/linkedintool/util/AuthUtil.java @@ -0,0 +1,35 @@ +package com.hanstack.linkedintool.util; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Objects; + +public class AuthUtil { + public static boolean isLogin() { + try { + return Objects.nonNull(getCurrentUser()); + } catch (Exception e) { + return false; + } + + } + + public static UserDetails getCurrentUser() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication.getPrincipal() instanceof String || Objects.isNull(authentication.getPrincipal())) { + return null; + } + + UserDetails userDetails = (UserDetails) authentication.getPrincipal(); + + if (StringUtils.isEmpty(userDetails.getUsername())) { + return null; + } + + return userDetails; + } +}