Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] OAuth2 로그인 및 회원 관리 기능 추가 및 수정 #132

Merged
merged 2 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.samsamohoh.webtoonsearch.adapter.config;

import com.samsamohoh.webtoonsearch.application.port.out.SaveMemberPort;
import com.samsamohoh.webtoonsearch.application.service.PrincipalOauth2UserService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
Expand All @@ -17,6 +19,18 @@
@EnableWebSecurity
public class SecurityConfig {

private final SaveMemberPort saveMemberPort;

// SaveMemberPort를 생성자로 주입받도록 수정합니다.
public SecurityConfig(SaveMemberPort saveMemberPort) {
this.saveMemberPort = saveMemberPort;
}

@Bean
public PrincipalOauth2UserService principalOauth2UserService() {
return new PrincipalOauth2UserService(saveMemberPort);
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
Expand All @@ -28,9 +42,21 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
.requestMatchers("/actuator/**").permitAll()
.anyRequest().authenticated()
)
// .oauth2Login(oauth2 -> oauth2
// .defaultSuccessUrl("/", true) // 로그인 성공 후 리다이렉트 URL
// )
.oauth2Login(oauth2Login ->
oauth2Login
.loginPage("/")
.defaultSuccessUrl("http://localhost:8081")
.failureUrl("/")
.userInfoEndpoint(userInfoEndpoint ->
userInfoEndpoint.userService(principalOauth2UserService())
)
)
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("http://localhost:8081")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
)
.cors(withDefaults()); // 기본 CORS 설정 적용

return http.build();
Expand All @@ -49,3 +75,4 @@ public CorsConfigurationSource corsConfigurationSource() {
return source;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberPersistenceAdapter extends JpaRepository<RegisterMemberEntity, String> {
public interface MemberPersistenceAdapter extends JpaRepository<RegisterMemberEntity, Long> {
RegisterMemberEntity findByProviderId(String providerId);
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package com.samsamohoh.webtoonsearch.adapter.persistence;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
Expand All @@ -16,20 +13,26 @@
public class RegisterMemberEntity {

@Id
@Column(name = "naver_id")
private String naverId;
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "provider_id")
private String providerId;

private String email;
private String gender;
private String age;
private String nickname;

private String provider;

@Builder
public RegisterMemberEntity(String naverId, String email, String gender, String age, String nickname) {
this.naverId = naverId;
public RegisterMemberEntity(String providerId, String email, String gender, String age, String nickname, String provider) {
this.providerId = providerId;
this.email = email;
this.gender = gender;
this.age = age;
this.nickname = nickname;
this.provider = provider;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import com.samsamohoh.webtoonsearch.adapter.persistence.MemberPersistenceAdapter;
import com.samsamohoh.webtoonsearch.adapter.persistence.RegisterMemberEntity;
import com.samsamohoh.webtoonsearch.application.port.in.member.RegisterMemberCommand;
import com.samsamohoh.webtoonsearch.application.port.in.member.MemberResponseDTO;
import com.samsamohoh.webtoonsearch.application.port.out.SaveMemberPort;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
Expand All @@ -14,14 +14,34 @@ public class MemberRecordAdapter implements SaveMemberPort {
private final MemberPersistenceAdapter memberPersistenceAdapter;

@Override
public void saveMember(RegisterMemberCommand command) {
public MemberResponseDTO saveMember(MemberResponseDTO command) {
RegisterMemberEntity entity = RegisterMemberEntity.builder()
.naverId(command.getNaverId())
.providerId(command.getProviderId())
.email(command.getEmail())
.gender(command.getGender())
.age(command.getAge())
.nickname(command.getNickname())
.provider(command.getProvider())
.build();

memberPersistenceAdapter.save(entity);

return command; // 필요한 경우 savedEntity를 기반으로 새로운 DTO를 반환하도록 수정
}

@Override
public MemberResponseDTO findMemberByProviderId(String providerId) {
RegisterMemberEntity entity = memberPersistenceAdapter.findByProviderId(providerId);
if (entity != null) {
return new MemberResponseDTO(
entity.getProviderId(),
entity.getEmail(),
entity.getAge(),
entity.getGender(),
entity.getNickname(),
entity.getProvider()
);
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.samsamohoh.webtoonsearch.adapter.web.member;

import java.util.Map;

public class NaverUserInfo implements OAuth2UserInfo{

private final Map<String, Object> attributes;
private final Map<String, Object> attributesResponse;

public NaverUserInfo(Map<String, Object> attributes) {
this.attributes = (Map<String, Object>) attributes.get("response");
this.attributesResponse = (Map<String, Object>) attributes.get("response");
}

@Override
public Map<String, Object> getAttributes() {
return attributes;
}

@Override
public String getProviderId() {
return attributesResponse.get("id").toString();
}

@Override
public String getProvider() {
return "naver";
}

@Override
public String getEmail() {
return attributesResponse.get("email").toString();
}

@Override
public String getName() {
return attributesResponse.get("name").toString();
}

@Override
public String getAge() {
return attributesResponse.get("age").toString();
}

@Override
public String getGender() {
return attributesResponse.get("gender").toString();
}

@Override
public String getNickname() {
return attributesResponse.get("nickname").toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.samsamohoh.webtoonsearch.adapter.web.member;

import java.util.Map;

public interface OAuth2UserInfo {

Map<String, Object> getAttributes();
String getProviderId();
String getEmail();
String getAge();
String getGender();
String getNickname();
String getProvider();
String getName();

}
Original file line number Diff line number Diff line change
@@ -1,32 +1,33 @@
package com.samsamohoh.webtoonsearch.adapter.web.member;

import com.samsamohoh.webtoonsearch.application.port.in.member.RegisterMemberCommand;
import com.samsamohoh.webtoonsearch.application.port.in.member.RegisterMemberUseCase;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;


@RestController
@RequestMapping("/logins")
@RequiredArgsConstructor
public class OAuthController {

private final RegisterMemberUseCase registerMemberUseCase;

@PostMapping("/naver")
public ResponseEntity<String> registerMember(@RequestBody OAuthResponse oAuthResponse) {
RegisterMemberCommand command = new RegisterMemberCommand(
oAuthResponse.getEmail(),
oAuthResponse.getGender(),
oAuthResponse.getNaverId(),
oAuthResponse.getAge(),
oAuthResponse.getNickname()
);
registerMemberUseCase.registerMember(command);
return ResponseEntity.ok("Member registered successfully");

@GetMapping("/loginInfo")
@ResponseBody
public Map<String, Object> oauthLoginInfo(Authentication authentication, @AuthenticationPrincipal OAuth2User oAuth2UserPrincipal) {

OAuth2User oAuth2User = (OAuth2User) authentication.getPrincipal();
Map<String, Object> attributes = oAuth2User.getAttributes();

System.out.println("attributes::" + attributes);

return attributes;
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.samsamohoh.webtoonsearch.adapter.web.member;

import lombok.Getter;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.oauth2.core.user.OAuth2User;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;

@Getter
@ToString
public class PrincipalDetails implements UserDetails, OAuth2User {

private final String email;
private final String gender;
private final String providerId;
private final String age;
private final String nickname;
private final String provider;

private final OAuth2UserInfo oAuth2UserInfo;

public PrincipalDetails(String email, String gender, String providerId, String age, String nickname, String provider, OAuth2UserInfo oAuth2UserInfo) {
this.email = email;
this.gender = gender;
this.providerId = providerId;
this.age = age;
this.nickname = nickname;
this.provider = provider;
this.oAuth2UserInfo = oAuth2UserInfo;
}


@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptyList();
}

@Override
public String getPassword() {
return null;
}

@Override
public String getUsername() {
return this.email;
}

@Override
public Map<String, Object> getAttributes() {
return oAuth2UserInfo.getAttributes();
}

@Override
public String getName() {
return oAuth2UserInfo.getProviderId();
}

public String getProvider() {
return this.provider;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
import lombok.Value;

@Value
public class RegisterMemberCommand {
public class MemberResponseDTO {

String providerId;
String email;
String gender;
String naverId;
String age;
String gender;
String nickname;

String provider;

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.samsamohoh.webtoonsearch.application.port.in.member;

public interface RegisterMemberUseCase {
void registerMember(RegisterMemberCommand command);

boolean updateMemberInfo(MemberResponseDTO memberResponseDTO);
MemberResponseDTO getMemberInfo(String providerId);

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.samsamohoh.webtoonsearch.application.port.out;


import com.samsamohoh.webtoonsearch.application.port.in.member.RegisterMemberCommand;
import com.samsamohoh.webtoonsearch.application.port.in.member.MemberResponseDTO;

public interface SaveMemberPort {
void saveMember(RegisterMemberCommand registerMemberCommand);
MemberResponseDTO saveMember(MemberResponseDTO memberResponseDTO);
MemberResponseDTO findMemberByProviderId(String providerId);
}
Loading