Feat: 로그인 기능 구현 - S11P21S002-15
This commit is contained in:
parent
c0661f03d5
commit
a603ddd2b2
@ -0,0 +1,22 @@
|
||||
package com.worlabel.domain.auth.attribute;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Getter
|
||||
@ToString
|
||||
@RequiredArgsConstructor
|
||||
public abstract class OAuth2Attribute {
|
||||
private final Map<String,Object> attributes;
|
||||
|
||||
public abstract String getId();
|
||||
|
||||
public abstract String getName();
|
||||
|
||||
public abstract String getEmail();
|
||||
|
||||
public abstract String getProfileImage();
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package com.worlabel.domain.auth.attribute;
|
||||
|
||||
import com.worlabel.domain.auth.attribute.impl.GoogleAttribute;
|
||||
import com.worlabel.domain.auth.entity.ProviderType;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class OAuth2AttributeFactory {
|
||||
public static OAuth2Attribute parseAttribute(ProviderType provider, Map<String, Object> attributes){
|
||||
OAuth2Attribute oAuth2Attribute = null;
|
||||
switch (provider) {
|
||||
case GOOGLE :
|
||||
oAuth2Attribute = new GoogleAttribute(attributes);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("지원하지 않는 소셜 로그인입니다.");
|
||||
};
|
||||
return oAuth2Attribute;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.worlabel.domain.auth.attribute.impl;
|
||||
|
||||
import ch.qos.logback.core.util.StringUtil;
|
||||
import com.worlabel.domain.auth.attribute.OAuth2Attribute;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class GoogleAttribute extends OAuth2Attribute {
|
||||
|
||||
public GoogleAttribute(Map<String,Object> attributes) {
|
||||
super(attributes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return super.getAttributes().get("sub").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return super.getAttributes().get("name").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEmail() {
|
||||
return super.getAttributes().get("email").toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProfileImage() {
|
||||
return super.getAttributes().get("picture").toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.worlabel.domain.auth.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/auth")
|
||||
public class AuthController {
|
||||
|
||||
@GetMapping("/login")
|
||||
public String login() {
|
||||
return "성공";
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
package com.worlabel.domain.auth.service;
|
||||
|
||||
import com.worlabel.domain.auth.attribute.OAuth2Attribute;
|
||||
import com.worlabel.domain.auth.attribute.OAuth2AttributeFactory;
|
||||
import com.worlabel.domain.auth.entity.ProviderType;
|
||||
import com.worlabel.domain.member.entity.Member;
|
||||
import com.worlabel.domain.member.repository.MemberRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.DefaultOAuth2User;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2User;
|
||||
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* OAuth2 사용자 서비스 클래스
|
||||
* OAuth2 인증을 통해 사용자 정보를 로드하고 처리하는 역할
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CustomOAuth2UserService extends DefaultOAuth2UserService {
|
||||
|
||||
private final MemberRepository memberRepository;
|
||||
|
||||
@Override
|
||||
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
|
||||
OAuth2User user = super.loadUser(userRequest);
|
||||
log.debug("oAuth2User: {}", user.getAttributes());
|
||||
|
||||
ProviderType provider = ProviderType.valueOf(userRequest.getClientRegistration().getRegistrationId().toUpperCase());
|
||||
OAuth2Attribute attribute = OAuth2AttributeFactory.parseAttribute(provider, user.getAttributes());
|
||||
log.debug("provider: {}, user: {}", provider, user);
|
||||
|
||||
Member findMember = memberRepository.findByProviderMemberId(attribute.getId())
|
||||
.orElseGet(() -> {
|
||||
Member member = Member.of(attribute.getId(), attribute.getEmail(), attribute.getName(), attribute.getProfileImage());
|
||||
memberRepository.save(member);
|
||||
return member;
|
||||
});
|
||||
|
||||
return new DefaultOAuth2User(Collections.singleton(new OAuth2UserAuthority(user.getAttributes())),
|
||||
user.getAttributes(),
|
||||
"sub"
|
||||
);
|
||||
}
|
||||
}
|
@ -38,6 +38,18 @@ public class Member extends BaseEntity {
|
||||
@Enumerated(EnumType.STRING)
|
||||
private ProviderType provider = ProviderType.GOOGLE;
|
||||
|
||||
/**
|
||||
* 사용자 이메일
|
||||
*/
|
||||
@Column(name = "email",nullable = false, length = 40)
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* 사용자 닉네임
|
||||
*/
|
||||
@Column(name = "nickname",nullable = false, length = 20)
|
||||
private String nickname;
|
||||
|
||||
/**
|
||||
* 사용자 역할
|
||||
*/
|
||||
@ -56,4 +68,13 @@ public class Member extends BaseEntity {
|
||||
*/
|
||||
@OneToMany(mappedBy = "member", fetch = FetchType.LAZY,cascade = CascadeType.ALL, orphanRemoval = true)
|
||||
private List<Comment> commentList = new ArrayList<>();
|
||||
|
||||
public static Member of(String providerMemberId, String email, String nickname, String profileImage) {
|
||||
Member member = new Member();
|
||||
member.providerMemberId = providerMemberId;
|
||||
member.email = email;
|
||||
member.nickname = nickname;
|
||||
member.profileImage = profileImage;
|
||||
return member;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,10 @@
|
||||
package com.worlabel.domain.member.repository;
|
||||
|
||||
import com.worlabel.domain.member.entity.Member;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public interface MemberRepository extends JpaRepository<Member, Integer> {
|
||||
public Optional<Member> findByProviderMemberId(String providerMemberId);
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package com.worlabel.global.config;
|
||||
|
||||
import lombok.Builder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;
|
||||
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// HTTP 요청에 대한 인증 및 권한 설정
|
||||
.authorizeHttpRequests(auth -> auth
|
||||
// 경로는 모든 사용자가 접근 할 수 있도록 허용
|
||||
.requestMatchers("/**","/favicon.ico").permitAll()
|
||||
// 그 외의 모든 요청은 인증해야함
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
// OAuth2 로그인 설정
|
||||
.oauth2Login(oauth2 -> oauth2
|
||||
.userInfoEndpoint(userInfo ->
|
||||
// 사용자 정보를 처리하는 서비스로 DefaultOAuth2UserService
|
||||
userInfo.userService(new DefaultOAuth2UserService()))
|
||||
)
|
||||
// CSRF 보호 설정
|
||||
.csrf(csrf -> csrf // CSRF 보호 활성화 및 커스터마이징
|
||||
// CSRF토큰을 쿠키에 저장하도록 설정, HTTP-only 속성을 비활성화하여 자바스크립트에서 접근 가능하게 함
|
||||
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
|
||||
);
|
||||
// 설정을 바탕으로 SecurityFilterChain 빌드
|
||||
return http.build();
|
||||
}
|
||||
}
|
0
backend/src/main/resources/.gitkeep
Normal file
0
backend/src/main/resources/.gitkeep
Normal file
Loading…
Reference in New Issue
Block a user