- 구글 로그인은 API 적용만 해놓고 사용하지 않음 -> 추후 소셜 로그인 시 추가정보 입력을 통해 확장할 예정
- 각 플랫폼 API 사용법은 생략
- application-oauth.properties
#Google Login
spring.security.oauth2.client.registration.google.clientId= !클라이언트 ID!
spring.security.oauth2.client.registration.google.clientSecret= !클라이언트 비밀번호!
spring.security.oauth2.client.registration.google.scope=profile,email
#Naver Login
spring.security.oauth2.client.registration.naver.clientId = !클라이언트 ID!
spring.security.oauth2.client.registration.naver.clientSecret = !클라이언트 비밀번호!
spring.security.oauth2.client.registration.naver.redirectUri= {baseUrl}/{action}/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.naver.authorizationGrantType=authorization_code
spring.security.oauth2.client.registration.naver.scope = name,email, nickname
spring.security.oauth2.client.registration.naver.clientName=Naver
#Naver Login Provider
spring.security.oauth2.client.provider.naver.authorizationUri=https://nid.naver.com/oauth2.0/authorize
spring.security.oauth2.client.provider.naver.tokenUri=https://nid.naver.com/oauth2.0/token
spring.security.oauth2.client.provider.naver.userInfoUri=https://openapi.naver.com/v1/nid/me
spring.security.oauth2.client.provider.naver.userNameAttribute=response
- application.properties
#Login
spring.profiles.include=oauth
spring.h2.console.enabled=true
spring.jpa.defer-datasource-initialization=true
logging.level.org.hibernate.SQL = DEBUG
spring.jpa.properties.hibernate.format_sql = true
#sql trace
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
#unique URL ??
spring.datasource.generate-unique-name=false
#h2 DB URL
spring.datasource.url=jdbc:h2:mem:coffeedb
- config/auth/CustomOAuth2UserService
package com.example.CoffeeShop.config.auth;
import com.example.CoffeeShop.Entity.User;
import com.example.CoffeeShop.Repository.UserRepository;
import com.example.CoffeeShop.config.auth.DTO.OAuthAttributes;
import com.example.CoffeeShop.config.auth.DTO.SessionUser;
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 CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private final UserRepository userRepository;
private final HttpSession httpSession;
@Override
public OAuth2User loadUser(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 = saveOrUpdate(attributes);
httpSession.setAttribute("user", new SessionUser(user));
return new DefaultOAuth2User(
Collections.singleton(new SimpleGrantedAuthority(user.getRoleKey())),
attributes.getAttributes(),
attributes.getNameAttributeKey());
}
private User saveOrUpdate(OAuthAttributes attributes) {
User user = (User) userRepository.findByToken(attributes.getToken())
.map(entity -> entity.update(attributes.getName()))
.orElse(attributes.toEntity());
return userRepository.save(user);
}
}
- config/auth/SecurityConfig
package com.example.CoffeeShop.config.auth;
import lombok.RequiredArgsConstructor;
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;
@RequiredArgsConstructor
//Spring Security 활성화
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final CustomOAuth2UserService customOAuth2UserService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().headers().frameOptions().disable() //h2 사용을 위한 옵션 비활성화
.and().logout().logoutSuccessUrl("/") //로그아웃 성공 시 / 주소로 이동
.and().oauth2Login().userInfoEndpoint().userService(customOAuth2UserService); //userInterface 구현체 등록
}
}
- config/auth/DTO/OAuthAttributes
package com.example.CoffeeShop.config.auth.DTO;
import com.example.CoffeeShop.Entity.UserManage.Role;
import com.example.CoffeeShop.Entity.User;
import lombok.Builder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
@Getter
@Slf4j
public class OAuthAttributes {
private Map<String, Object> attributes;
private String nameAttributeKey;
private String name;
private String token;
private String birth;
private String phoneNum;
@Builder
public OAuthAttributes(Map<String, Object> attributes, String nameAttributeKey, String name, String token, String birth, String phoneNum) {
this.attributes = attributes;
this.nameAttributeKey = nameAttributeKey;
this.name = name;
this.token = token;
this.birth = birth;
this.phoneNum = phoneNum;
}
public static OAuthAttributes of(String registrationId, String userNameAttributeName, Map<String, Object> attributes) {
if ("naver".equals(registrationId)) {
return ofNaver("id", attributes);
}
return ofGoogle(userNameAttributeName, attributes);
}
private static OAuthAttributes ofGoogle(String userNameAttributeName, Map<String, Object> attributes) {
log.info("attribute : " +attributes);
return OAuthAttributes.builder()
.name((String) attributes.get("name"))
.token((String) attributes.get("email"))
.birth((String) attributes.get("age"))
.attributes(attributes)
.nameAttributeKey(userNameAttributeName)
.build();
}
private static OAuthAttributes ofNaver(String userNameAttributeName, Map<String, Object> attributes) {
Map<String, Object> response = (Map<String, Object>)attributes.get("response");
log.info("naver response : " + response);
return OAuthAttributes.builder()
.name((String) response.get("name"))
.token((String) response.get("id"))
.phoneNum((String) response.get("mobile"))
.birth((String) response.get("birthyear"))
.attributes(response)
.nameAttributeKey(userNameAttributeName)
.build();
}
public User toEntity() {
return User.builder()
.name(name)
.token(token)
.phoneNum(phoneNum)
.birth(birth)
.role(Role.GUEST)
.build();
}
}
- config/auth/DTO/SessionUser
package com.example.CoffeeShop.config.auth.DTO;
import com.example.CoffeeShop.Entity.User;
import lombok.Getter;
import java.io.Serializable;
@Getter
public class SessionUser implements Serializable {
private String name;
private String token;
public SessionUser(User user) {
this.name = user.getName();
this.token = user.getToken();
}
}
- config/auth/LoginUser
package com.example.CoffeeShop.config.auth;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.PARAMETER) //어노테이션이 생성될 수 있는 위치 지정
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginUser {
}
- config/auth/LoginUserArgumentResolver
package com.example.CoffeeShop.config.auth;
import com.example.CoffeeShop.config.auth.DTO.SessionUser;
import lombok.RequiredArgsConstructor;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpSession;
@RequiredArgsConstructor
@Component
public class LoginUserArgumentResolver implements HandlerMethodArgumentResolver {
private final HttpSession httpSession;
@Override
public boolean supportsParameter(MethodParameter parameter) {
boolean isLoginUserAnnotation = parameter.getParameterAnnotation(LoginUser.class) != null;
boolean isUserClass = SessionUser.class.equals(parameter.getParameterType());
return isLoginUserAnnotation && isUserClass;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer modelAndViewContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return httpSession.getAttribute("user");
}
}
- 뷰 페이지
GitHub - Pearlmoon997/CoffeeShop: CoffeeShop
CoffeeShop. Contribute to Pearlmoon997/CoffeeShop development by creating an account on GitHub.
github.com
'프로젝트_ 커피주문 서비스' 카테고리의 다른 글
마이페이지 (0) | 2022.08.31 |
---|---|
주문하기 구현 (0) | 2022.08.28 |
레이아웃, Member 변경 (0) | 2022.08.11 |
Store - Order 연결 (0) | 2022.08.09 |
Store CRUD (0) | 2022.08.08 |