From 9b6adc7e3223346fe67ad84599ca146cc29af68a Mon Sep 17 00:00:00 2001 From: HeeSung98 Date: Mon, 20 Nov 2023 13:22:13 +0900 Subject: [PATCH] =?UTF-8?q?=EC=86=8C=EC=85=9C=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- user/build.gradle | 2 + .../weather/user/config/SecurityConfig.java | 44 +++++++++--- .../user/security/dto/AuthUserDTO.java | 12 +++- .../user/security/filter/ApiCheckFilter.java | 17 +++++ .../security/handler/LoginSuccessHandler.java | 30 +++++++++ .../service/AuthUserDetailsService.java | 4 +- .../service/OAuth2UserDetailsService.java | 67 +++++++++++++++++++ 7 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 user/src/main/java/com/weather/user/security/filter/ApiCheckFilter.java create mode 100644 user/src/main/java/com/weather/user/security/handler/LoginSuccessHandler.java create mode 100644 user/src/main/java/com/weather/user/security/service/OAuth2UserDetailsService.java diff --git a/user/build.gradle b/user/build.gradle index 345bf54..04a6e7f 100644 --- a/user/build.gradle +++ b/user/build.gradle @@ -38,6 +38,8 @@ dependencies { testImplementation 'org.springframework.security:spring-security-test' //추가 implementation 'mysql:mysql-connector-java:8.0.31' + //추가 + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' } dependencyManagement { diff --git a/user/src/main/java/com/weather/user/config/SecurityConfig.java b/user/src/main/java/com/weather/user/config/SecurityConfig.java index 1c6dbf1..326e0d8 100644 --- a/user/src/main/java/com/weather/user/config/SecurityConfig.java +++ b/user/src/main/java/com/weather/user/config/SecurityConfig.java @@ -1,25 +1,49 @@ package com.weather.user.config; +import com.weather.user.security.filter.ApiCheckFilter; +import com.weather.user.security.handler.LoginSuccessHandler; +import com.weather.user.security.service.AuthUserDetailsService; +import com.weather.user.service.UserService; +import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +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.crypto.password.PasswordEncoder; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @Configuration +@RequiredArgsConstructor public class SecurityConfig { + private final AuthUserDetailsService authUserDetailsService; + @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } -// @Bean -// public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ -// http.authorizeHttpRequests((auth) -> auth -// .requestMatchers("/test", "/hello").permitAll() -// .requestMatchers("/").hasRole("user")); -// http.formLogin((login) -> login.loginPage("/login")); -// http.csrf((csrf) -> csrf.disable()); -// -// return http.build(); -// } + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ + http.authorizeHttpRequests((auth) -> auth + .requestMatchers("/**").permitAll()); + http.csrf((csrf) -> csrf.disable()); + http.formLogin(login -> login.successHandler(loginSuccessHandler())); + http.oauth2Login(login -> login.successHandler(loginSuccessHandler())); + http.logout(Customizer.withDefaults()); + http.rememberMe(rememberMe -> rememberMe.tokenValiditySeconds(60*60*24*60).userDetailsService(authUserDetailsService)); + + http.addFilterBefore(apiCheckFilter(), UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } + + @Bean + public LoginSuccessHandler loginSuccessHandler() { + return new LoginSuccessHandler(passwordEncoder()); + } + + @Bean + public ApiCheckFilter apiCheckFilter() { + return new ApiCheckFilter(); + } } diff --git a/user/src/main/java/com/weather/user/security/dto/AuthUserDTO.java b/user/src/main/java/com/weather/user/security/dto/AuthUserDTO.java index 3175030..4de5f31 100644 --- a/user/src/main/java/com/weather/user/security/dto/AuthUserDTO.java +++ b/user/src/main/java/com/weather/user/security/dto/AuthUserDTO.java @@ -8,22 +8,28 @@ import org.springframework.security.core.userdetails.User; import java.util.Collection; +import java.util.Map; @Log4j2 @Getter @Setter @ToString public class AuthUserDTO extends User { - private String email, password; + private String email, password, name, nickname, image; private boolean fromSocial, status; - public AuthUserDTO(String username, String password, boolean fromSocial, boolean status, + Map attributes; + + public AuthUserDTO(String username, String password, String name, String nickname,String image, boolean fromSocial, boolean status, Collection authorities) { super(username, password, authorities); this.email = username; - this.fromSocial = fromSocial; this.password = password; + this.name = name; + this.nickname = nickname; + this.image = image; + this.fromSocial = fromSocial; this.status = status; } } diff --git a/user/src/main/java/com/weather/user/security/filter/ApiCheckFilter.java b/user/src/main/java/com/weather/user/security/filter/ApiCheckFilter.java new file mode 100644 index 0000000..e53eb1a --- /dev/null +++ b/user/src/main/java/com/weather/user/security/filter/ApiCheckFilter.java @@ -0,0 +1,17 @@ +package com.weather.user.security.filter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +public class ApiCheckFilter extends OncePerRequestFilter { + @Override + public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + } +} diff --git a/user/src/main/java/com/weather/user/security/handler/LoginSuccessHandler.java b/user/src/main/java/com/weather/user/security/handler/LoginSuccessHandler.java new file mode 100644 index 0000000..36acc76 --- /dev/null +++ b/user/src/main/java/com/weather/user/security/handler/LoginSuccessHandler.java @@ -0,0 +1,30 @@ +package com.weather.user.security.handler; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.log4j.Log4j2; +import org.springframework.security.core.Authentication; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.RedirectStrategy; +import org.springframework.security.web.authentication.AuthenticationSuccessHandler; + +import java.io.IOException; + +@Log4j2 +public class LoginSuccessHandler implements AuthenticationSuccessHandler { + private RedirectStrategy redirectStrategy; + private PasswordEncoder passwordEncoder; + + public LoginSuccessHandler(PasswordEncoder passwordEncoder) { + this.passwordEncoder = passwordEncoder; + } + + @Override + public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws IOException, ServletException { + log.info("ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ"); + log.info("인증에 성공했습니다."); + } +} diff --git a/user/src/main/java/com/weather/user/security/service/AuthUserDetailsService.java b/user/src/main/java/com/weather/user/security/service/AuthUserDetailsService.java index fc5937d..f9cf6b5 100644 --- a/user/src/main/java/com/weather/user/security/service/AuthUserDetailsService.java +++ b/user/src/main/java/com/weather/user/security/service/AuthUserDetailsService.java @@ -22,6 +22,7 @@ public class AuthUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { + log.info("ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ"); log.info("email: " + email); Optional optionalUser = userRepository.findByEmail(email, false); @@ -34,7 +35,8 @@ public UserDetails loadUserByUsername(String email) throws UsernameNotFoundExcep log.info("user: " + user.getPassword()); AuthUserDTO authUserDTO = new AuthUserDTO( - user.getEmail(), user.getPassword(), user.isFromSocial(), user.isStatus(), + user.getEmail(), user.getPassword(), user.getImage(), user.getName(), user.getNickname(), + user.isFromSocial(), user.isStatus(), user.getRoleSet().stream().map((role) -> new SimpleGrantedAuthority("Role_" + role.name())).collect(Collectors.toSet()) ); diff --git a/user/src/main/java/com/weather/user/security/service/OAuth2UserDetailsService.java b/user/src/main/java/com/weather/user/security/service/OAuth2UserDetailsService.java new file mode 100644 index 0000000..87307de --- /dev/null +++ b/user/src/main/java/com/weather/user/security/service/OAuth2UserDetailsService.java @@ -0,0 +1,67 @@ +package com.weather.user.security.service; + +import com.weather.user.entity.User; +import com.weather.user.entity.UserRole; +import com.weather.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.log4j.Log4j2; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Log4j2 +@Service +@RequiredArgsConstructor +public class OAuth2UserDetailsService extends DefaultOAuth2UserService { + private final UserRepository userRepository; + private final PasswordEncoder passwordEncoder; + + @Override + public OAuth2User loadUser(OAuth2UserRequest request) throws OAuth2AuthenticationException { + log.info("ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ"); + log.info("request: " + request); + + log.info("clientName: " + request.getClientRegistration().getClientName()); + log.info("params: " + request.getAdditionalParameters()); + + OAuth2User oAuth2User = super.loadUser(request); + + oAuth2User.getAttributes().forEach((key, value) -> { + log.info(key + ": " + value); + }); + + User user = saveSocialUser(oAuth2User); + + return oAuth2User; + } + + private User saveSocialUser(OAuth2User oAuth2User) { + log.info("ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ"); + String email = oAuth2User.getAttribute("email"); + String image = oAuth2User.getAttribute("picture"); + Optional optionalUser = userRepository.findByEmail(email, true); + + if(optionalUser.isPresent()) { + return optionalUser.get(); + } else { + User socialUser = User.builder() + .email(email) + .password(passwordEncoder.encode("1234")) + .image(image) + .fromSocial(true) + .status(true) + .build(); + + socialUser.addRole(UserRole.USER); + + userRepository.save(socialUser); + + return socialUser; + } + } +}