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/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); + } +} 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); + } + } +} 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(); + } +} 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(); + } +}