
์ฅ์ :
๋จ์ :

1 ~ 3 : ์ธ์ฆ ์ฒ๋ฆฌ ์๋ฃ (code)
4 ~ 5 : ๋ค์ด๋ฒ ์ ๋ณด์ ์ ๊ทผ ๊ถํ ๋ถ์ฌ (Access Token)
์นํ์ด์ง๊ฐ ์ ์ฌ ๋์ ๋ค์ด๋ฒ์ ์ ๊ทผ์ด ๊ฐ๋ฅํด์ง๋๋ค.
#OAuth2
spring.security.oauth2.client.registration.naver.client-id=[ํด๋ผ์ด์ธํธID]
spring.security.oauth2.client.registration.naver.client-secret=[ํด๋ผ์ด์ธํธ secret]
spring.security.oauth2.client.registration.naver.scope=email, nickname
spring.security.oauth2.client.registration.naver.client-name=Naver
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.redirect-uri=http://localhost:8080/login/oauth2/code/naver
# provider
spring.security.oauth2.client.provider.naver.authorization-uri=https://nid.naver.com/oauth2.0/authorize
spring.security.oauth2.client.provider.naver.token-uri=https://nid.naver.com/oauth2.0/token
spring.security.oauth2.client.provider.naver.user-info-uri=https://openapi.naver.com/v1/nid/me
spring.security.oauth2.client.provider.naver.user-name-attribute=response
1. SecurityConfiguration ํด๋์ค์์ OAuth2 ์ค์ ํด์ค๋๋ค.
@Configuration
@EnableMethodSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {
private final Oauth2MemberService oauth2MemberService;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(csrf -> csrf.disable())
.formLogin(login -> login.loginPage("/member/login"))
.authorizeHttpRequests(authorize -> authorize
.anyRequest()
.permitAll()
)
// OAuth2 ๋ก๊ทธ์ธ ๊ตฌ์ฑ์ ์ํ ์ค์ ๊ฐ์ ธ์ด
.oauth2Login(oauth2 -> oauth2
// ์ฌ์ฉ์ ์ ๋ณด ์๋ํฌ์ธํธ์ ๋ํ ์ค์ ์ถ๊ฐ
.userInfoEndpoint(infoEndpoint ->
// ์ฌ์ฉ์ ์๋น์ค ๊ตฌ์ฑ(๋ก๊ทธ์ธ ์ฑ๊ณต ํ ์ฌ์ฉ์ ์ ๋ณด ์ฒ๋ฆฌ)
infoEndpoint.userService(oauth2MemberService)));
return http.build();
}
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
.csrf : CSRF ๋นํ์ฑํ์ฌ ๊ณต๊ฒฉ์ ๋ฐฉ์งํฉ๋๋ค..formLogin : ๋ก๊ทธ์ธ ํ์ด์ง ๋ฐ๋ก ์ค์ ํฉ๋๋ค..authorizeHttpRequests : ๋ชจ๋ ์ฌ๋์๊ฒ HTTP ์์ฒญ์ ํ์ฉํฉ๋๋ค. ๋ชจ๋ ์์ฒญ์ ๋ํ ๊ถํ์ ๋ถ์ฌํฉ๋๋ค..oauth2Login : OAuth2๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค. ๋ก๊ทธ์ธ ์ฑ๊ณต ํ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ฒ๋ฆฌํฉ๋๋ค.2. OAuth2MemberInfo ์ธํฐํ์ด์ค
public interface OAuth2MemberInfo {
String getEmail();
String getProvider();
String getProviderId();
String getNickName();
}
3. NaverMemberInfo ํด๋์ค (OAuth2MemberInfo ๊ตฌํ)
@AllArgsConstructor
public class NaverMemberInfo implements OAuth2MemberInfo {
private Map<String, Object> attributes;
// naver OAuth2๋ก๋ถํฐ ๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด ์ถ์ถ
@Override
public String getProviderId() {
return (String) attributes.get("id");
}
@Override
public String getNickName() {
return (String) attributes.get("nickname");
}
@Override
public String getEmail() {
return (String) attributes.get("email");
}
@Override
public String getProvider() {
return "naver";
}
}
OAuth2MemberInfo ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ์ฌ ๋ค์ด๋ฒ๋ก๋ถํฐ ๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์ถ์ถํฉ๋๋ค.
๋ค์ด๋ฒ์ attributes์์ ์ฐ๋ฆฌ๊ฐ ํ์ํ response์ ํ์์ด Map์ผ๋ก ๋์ด ์์ด Map์ ์ฌ์ฉํฉ๋๋ค.

getXXXX() : ๋ค์ด๋ฒ๋ก๋ถํฐ ๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด์์ ํค์ ํด๋นํ๋ ๊ฐ์ ์ถ์ถํฉ๋๋ค.
getProvider() : ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ ์ ๊ณต์๋ฅผ ๋ฐํํฉ๋๋ค. ์ ๊ณต์๋ naver์
๋๋ค.
4. Oauth2MemberService ํด๋์ค(DefaultOAuth2UserService)
@Service
@RequiredArgsConstructor
public class Oauth2MemberService extends DefaultOAuth2UserService {
private final MemberMapper mapper;
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
System.out.println("userRequest.getAccessToken().getTokenValue() = " + userRequest.getAccessToken().getTokenValue());
System.out.println("userRequest.getClientRegistration() = " + userRequest.getClientRegistration());
System.out.println("userRequest.getClientRegistration().getRegistrationId() = " + userRequest.getClientRegistration().getRegistrationId());
OAuth2User oAuth2User = super.loadUser(userRequest); //๋ค์ด๋ฒ ์ฌ์ฉ์ ์ ๋ณด ๋ก๋
System.out.println("oAuth2User = " + oAuth2User.getAttributes());
String platform = userRequest.getClientRegistration().getRegistrationId(); //๋ก๊ทธ์ธํ ํด๋ผ์ด์ธํธ์ ๋ฑ๋ก ID
OAuth2MemberInfo response = null;
if (platform.equals("naver")) {
System.out.println("๋ค์ด๋ฒ ๋ก๊ทธ์ธ ์์ฒญ");
response = new NaverMemberInfo((Map) oAuth2User.getAttributes().get("response")); //๋ค์ด๋ฒ์ ์๋ ์ฌ์ฉ์ ์ ๋ณด ์ถ์ถ
System.out.println(response);
}
// DB์ ์ ์ฅ
Member member = mapper.selectByEmail(response.getEmail());
if (member == null) {
member = Member
.builder()
.email(response.getEmail())
.nickName(response.getNickName())
.password(userRequest.getAccessToken().getTokenValue())
.build();
// ๋ค์ด๋ฒ์์ ๋ฐ์ ์ด๋ฉ์ผ ์กฐํ ํ ํด๋น ์ด๋ฉ์ผ์ด ์๋ ๊ฒฝ์ฐ insert
System.out.println("์ต์ด");
mapper.insert(member);
}
return new CustomOauth2MemberDetails(member, oAuth2User.getAttributes());
}
}
DefaultOAuth2UserService๋ฅผ ์์๋ฐ์ loadUser๋ฅผ ๊ตฌํํฉ๋๋ค. loadUserByUsername ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๊ณ OAuth๋ฅผ ์ฌ์ฉํ ๋ก๊ทธ์ธ์ loadUser ๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ก๊ทธ์ธ ์ดํ ์ฒ๋ฆฌ๋ฅผ ์ํ ๋ฉ์๋๋ฅผ ํธ์ถํฉ๋๋ค.super.loadUser(userRequest) : OAuth2 ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ต๋๋ค.platform : ํด๋ผ์ด์ธํธ์ ๋ฑ๋ก ID๋ฅผ ๊ฐ์ ธ์ ์ ๊ณต์๋ฅผ ์๋ณํฉ๋๋ค. ํ๋ซํผ๋ง๋ค ID๊ฐ ๋ค๋ฆ
๋๋ค.NaverMemberInfo ํด๋์ค์ ์์ฑ์์์๋ response๋ผ๋ ํค์ ํด๋นํ๋ ๊ฐ์ Map์ผ๋ก ๋ณํํ์ฌ response ๊ฐ์ฒด์ ์ ์ฅํฉ๋๋ค. 5. CustomOauth2UserDetails ํด๋์ค (UserDetails, OAuth2User ์ธํฐํ์ด์ค ๊ตฌํ)
public class CustomOauth2MemberDetails implements UserDetails, OAuth2User {
private Member member;
private Map<String, Object> attributes; // ๋ค์ด๋ฒ์์ ๋ฐ์์จ ์ ๋ณด
public CustomOauth2MemberDetails(Member member, Map<String, Object> attributes) {
this.member = member;
this.attributes = attributes;
}
public CustomOauth2MemberDetails(Member member) {
this.member = member;
}
@Override
public String getName() {
return null;
}
@Override
public String getPassword() {
return member.getPassword();
}
@Override
public String getUsername() {
return member.getNickName();
}
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
UserDetails๋ ํ์๊ฐ์
, ๋ก๊ทธ์ธ ํ๋ก์ธ์ค๋ฅผ ์ง์ ๊ตฌํํ ๊ฒฝ์ฐ ์ฌ์ฉํ๊ณ OAuth2User๋ ์์
๋ก๊ทธ์ธ ๊ตฌํํ ๊ฒฝ์ฐ ์ฌ์ฉํฉ๋๋ค.UserDetails, OAuth2User๋ ํ์ ์ ๋ณด๋ฅผ ๋ฐ๋ก ๊ฐ์ง๊ณ ์์ง ์์ ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ์ฌ ์ฌ์ฉ์์ ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค.
- OAuth2MemberInfo ์ธํฐํ์ด์ค : ๋ค์ด๋ฒ์ ๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ค๋ฃจ๋ฉฐ ๊ฐ ์์ฑ์ ๋ํ getXX() ๋ฉ์๋๋ฅผ ์ ์ํฉ๋๋ค.
- NaverMemberInfo ํด๋์ค : ๋ค์ด๋ฒ๋ก ๋ถํฐ ๋ฐ์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ถ์ถํฉ๋๋ค. ์ด ๋ OAuth2MemberInfo ์ธํฐํ์ด์ค์ getXX() ๋ฉ์๋๋ฅผ ๊ตฌํํ์ฌ ์ถ์ถํฉ๋๋ค.
- Oauth2MemberService ํด๋์ค : ์ถ์ถํด์จ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์ฒ๋ฆฌํ๊ณ DB์ ์ ์ฅํฉ๋๋ค.
- CustomOauth2UserDetails ํด๋์ค : ๋ค์ด๋ฒ์์ ๋ฐ์์จ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ๋ค์ด๋ฒ ์์ ๋ก๊ทธ์ธ ์ฌ์ฉ์๋ฅผ ์ธ์ฆํ๊ณ ๊ถํ์ ๋ถ์ฌํฉ๋๋ค.

๋ค์ด๋ฒ์ ๋ก๊ทธ์ธ์ด ๋์ด ์์ง ์์ ๊ฒฝ์ฐ,

DB์ ์ ์ฅ
