From 9c93c74c8245cb0a131bbab439cf5d98b124cae5 Mon Sep 17 00:00:00 2001 From: Gobukgol Date: Wed, 15 Jul 2020 15:05:50 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat(AccessUser):=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=EC=9A=A9=20User=20Dto=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++-- .../security/dto/AccessUser.java | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/studymouse/studymouseserver/security/dto/AccessUser.java diff --git a/build.gradle b/build.gradle index 1b95e56..1040278 100644 --- a/build.gradle +++ b/build.gradle @@ -21,8 +21,8 @@ repositories { dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' -// implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' -// implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' + implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' compileOnly 'org.projectlombok:lombok' diff --git a/src/main/java/com/studymouse/studymouseserver/security/dto/AccessUser.java b/src/main/java/com/studymouse/studymouseserver/security/dto/AccessUser.java new file mode 100644 index 0000000..36aab86 --- /dev/null +++ b/src/main/java/com/studymouse/studymouseserver/security/dto/AccessUser.java @@ -0,0 +1,18 @@ +package com.studymouse.studymouseserver.security.dto; + +import com.studymouse.studymouseserver.user.User; +import lombok.Getter; + +@Getter +public class AccessUser { + + private String name; + private String email; + private String picture; + + public AccessUser(final User user) { + this.name = user.getName(); + this.email = user.getEmail(); + this.picture = user.getPicture(); + } +} From cd5beadad0ea8372769430d6591c5fc2ba83e704 Mon Sep 17 00:00:00 2001 From: Gobukgol Date: Wed, 15 Jul 2020 15:07:20 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat(OAuthAttributes):=20OAuth=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=EC=8B=9C=20=EB=B0=98=ED=99=98=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20=EC=A0=84=EB=8B=AC?= =?UTF-8?q?=ED=95=98=EB=8A=94=20Dto=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/dto/OAuthAttributes.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 src/main/java/com/studymouse/studymouseserver/security/dto/OAuthAttributes.java diff --git a/src/main/java/com/studymouse/studymouseserver/security/dto/OAuthAttributes.java b/src/main/java/com/studymouse/studymouseserver/security/dto/OAuthAttributes.java new file mode 100644 index 0000000..f49ee9a --- /dev/null +++ b/src/main/java/com/studymouse/studymouseserver/security/dto/OAuthAttributes.java @@ -0,0 +1,51 @@ +package com.studymouse.studymouseserver.security.dto; + +import com.studymouse.studymouseserver.user.Role; +import com.studymouse.studymouseserver.user.User; +import lombok.Builder; +import lombok.Getter; + +import java.util.Map; + +@Getter +public class OAuthAttributes { + private Map attributes; + private String nameAttributeKey; + private String name; + private String email; + private String picture; + + @Builder + public OAuthAttributes(final Map attributes, final String nameAttributeKey, final String name, final String email, final String picture) { + this.attributes = attributes; + this.nameAttributeKey = nameAttributeKey; + this.name = name; + this.email = email; + this.picture = picture; + } + + + public static OAuthAttributes of(final String registrationId, final String userNameAttributeName, final Map attributes) { + return ofGoogle(userNameAttributeName, attributes); + } + + private static OAuthAttributes ofGoogle(final String userNameAttributeName, final Map attributes) { + return OAuthAttributes.builder() + .name((String) attributes.get("name")) + .email((String) attributes.get("email")) + .picture((String) attributes.get("picture")) + .attributes(attributes) + .nameAttributeKey(userNameAttributeName) + .build(); + } + + + public User toEntity() { + return User.builder() + .name(name) + .email(email) + .picture(picture) + .role(Role.USER) + .build(); + } +} From 97f876f5d1fdb559fb362b9e2cadb268551d090e Mon Sep 17 00:00:00 2001 From: Gobukgol Date: Wed, 15 Jul 2020 15:14:34 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat(CustomOAuthUserService):=20OAuth=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=84=B1=EA=B3=B5=EC=8B=9C=20?= =?UTF-8?q?=ED=9B=84=EC=86=8D=EC=A1=B0=EC=B9=98=EB=A5=BC=20=EC=A7=84?= =?UTF-8?q?=ED=96=89=ED=95=A0=20OAuth2UserService=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=EC=B2=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit OAuth2 로그인 성공 후 DB에 해당 유저가 없을 경우 DB 저장 후 세션을 저장함 --- .../security/CustomOAuthUserService.java | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 src/main/java/com/studymouse/studymouseserver/security/CustomOAuthUserService.java diff --git a/src/main/java/com/studymouse/studymouseserver/security/CustomOAuthUserService.java b/src/main/java/com/studymouse/studymouseserver/security/CustomOAuthUserService.java new file mode 100644 index 0000000..d6c91b7 --- /dev/null +++ b/src/main/java/com/studymouse/studymouseserver/security/CustomOAuthUserService.java @@ -0,0 +1,56 @@ +package com.studymouse.studymouseserver.security; + +import com.studymouse.studymouseserver.security.dto.AccessUser; +import com.studymouse.studymouseserver.security.dto.OAuthAttributes; +import com.studymouse.studymouseserver.user.User; +import com.studymouse.studymouseserver.user.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.user.DefaultOAuth2User; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.stereotype.Service; + +import javax.servlet.http.HttpSession; +import java.util.Collections; + +@RequiredArgsConstructor +@Service +public class CustomOAuthUserService implements OAuth2UserService { + + private final UserRepository userRepository; + private final HttpSession httpSession; + + @Override + public OAuth2User loadUser(final OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { + OAuth2UserService delegate = new DefaultOAuth2UserService(); + OAuth2User oAuth2User = delegate.loadUser(userRequest); + + String registrationId = userRequest.getClientRegistration().getRegistrationId(); + String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails() + .getUserInfoEndpoint() + .getUserNameAttributeName(); + + OAuthAttributes attributes = OAuthAttributes.of(registrationId, userNameAttributeName, oAuth2User.getAttributes()); + + User user = save(attributes); + + httpSession.setAttribute("user", new AccessUser(user)); + + return new DefaultOAuth2User( + Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey())), + attributes.getAttributes(), + attributes.getNameAttributeKey() + ); + } + + private User save(final OAuthAttributes attributes) { + User user = userRepository.findByEmail(attributes.getEmail()) + .orElse(attributes.toEntity()); + + return userRepository.save(user); + } +} From 1fd822772960425ff50776f766367a7431c4e8c2 Mon Sep 17 00:00:00 2001 From: Gobukgol Date: Wed, 15 Jul 2020 15:18:06 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat(SecurityConfig):=20Spring=20Security?= =?UTF-8?q?=20configuration=20=ED=81=B4=EB=9E=98=EC=8A=A4=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 현재 "/api/word/" 관련한 API 호출의 경우 권한이 사용자일 경우에만 허용, 나머지는 권한 상관없이 허용 로그아웃 성공시 임시로 "/" url로 돌아가도록 설정 --- .../security/SecurityConfig.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/main/java/com/studymouse/studymouseserver/security/SecurityConfig.java diff --git a/src/main/java/com/studymouse/studymouseserver/security/SecurityConfig.java b/src/main/java/com/studymouse/studymouseserver/security/SecurityConfig.java new file mode 100644 index 0000000..9ddff00 --- /dev/null +++ b/src/main/java/com/studymouse/studymouseserver/security/SecurityConfig.java @@ -0,0 +1,37 @@ +package com.studymouse.studymouseserver.security; + +import com.studymouse.studymouseserver.user.Role; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; + +@Configuration +public class SecurityConfig { + + @RequiredArgsConstructor + @EnableGlobalMethodSecurity(securedEnabled = true) + static public class SecurityMajorConfig extends WebSecurityConfigurerAdapter { + + private final CustomOAuthUserService customOAuthUserService; + + @Override + protected void configure(final HttpSecurity http) throws Exception { + http + .csrf().disable() + .headers().frameOptions().disable() + .and() + .authorizeRequests() + .antMatchers("/api/word/**").hasRole(Role.USER.name()) + .anyRequest().permitAll() + .and() + .logout().logoutSuccessUrl("/") + .and() + .oauth2Login() + .userInfoEndpoint() + .userService(customOAuthUserService); + } + } +}