Oauth2 정리 , 백엔드만

Alex·2024년 10월 7일

시큐리티

목록 보기
1/2

인증: 네이버 소셜 로그인, 구글 소션 로그인
인가: 세션 방식을 통해서 경로별 접근 권한을 부여
인증정보 DB 저장 후 추가 정보 기입

로그인 요청이 들어오면 로그인 페이지로 리다이렉션 하는 필터가 이걸 받아서
네이버나 구글로 보낸다. 로그인이 되면 스프링 시큐리티쪽으로 인증 코드를 발급해준다.
이 코드를 갖고서 시큐리티에서 네이버나 구글로 다시 이 코드를 보내서 액세스 토큰을 받는다.
액세스 토큰을 갖고서 네이버나 구글로부터 유저 정보를 받는다.

로그인 요청이 오면 Oauth2AuthorizationRequestFilter에 의해서 네이버, 구글 인증 서버에 도착하게 된다.

외부 소셜 로그인 페이지가 응답이되고, 로그인이 성공되면 인증서버에 등록된 우리 서비스의 페이지로 리다이렉트 된다. 서비스 인증 서버에서는 특정한 Code를 날려준다.

이걸 다시 필터가 잡아서 OAuth2LoginAuthenticationProvider로 넘겨준다. 여기서 다시 네이버나 구글 서버로 Code 및 등록 정보를 전달해서 액세스토큰을 받는다. 이 액세스 토큰으로 다시 네이버와 같은 리소스 서버에 유저 정보를 요청한다.

이렇게 변수설정만 하면 알아서 로직이 진행된다.

설정하기

의존성 추가

implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http
                .csrf((csrf) -> csrf.disable());
        http
                .formLogin((login) -> login.disable());

        http
                .httpBasic((basic) -> basic.disable());

        http
                .oauth2Login(Customizer.withDefaults());

        http
                .authorizeHttpRequests((auth) -> auth
                        .requestMatchers("/", "/oauth2/**", "/login/**").permitAll()
                        .anyRequest().authenticated());

        return http.build();
    }
}

네이버 신청하기

콜백은 코드가 도착할 주소를 말한다.

http://localhost:8080/login/oauth2/code/naver

관습적으로 이렇게 사용한다.

코드 구현

@RequiredArgsConstructor
@Service
public class CustomerOauth2UserService extends DefaultOAuth2UserService {

    private final MemberRepository memberRepository;

    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {

        OAuth2User oauth2User = super.loadUser(userRequest);

        String registrationId = userRequest.getClientRegistration().getRegistrationId();
        OAuth2Response oAuth2Response;

        if(registrationId.equals("naver")){
            oAuth2Response = new NaverResponse(oauth2User.getAttributes());

        } else if(registrationId.equals("google")){
            oAuth2Response = new GoogleResponse(oauth2User.getAttributes());

        } else {

            return null;
        }

        String role = null;

        String userName = oAuth2Response.getProvider()+" "+oAuth2Response.getProviderId();
        Member existData = memberRepository.findByUserName(userName);

        if(existData == null){
            Member member = new Member(userName, oAuth2Response.getEmail(), "ROLE_USER");
            memberRepository.save(member);
        } else{
            role = existData.getRole();
            existData.setUserName(userName);
            existData.setLoginId(oAuth2Response.getEmail());
            existData.setRole("ROLE_USER");

        }

        return new CustomOauth2User(oAuth2Response, role);
    }
}
public interface OAuth2Response {

    String getProvider();

    String getProviderId();

    String getEmail();

    String getName();

}


public class GoogleResponse implements OAuth2Response{

    private final Map<String, Object> attributes;

    public GoogleResponse(Map<String, Object> attributes) {
        this.attributes = attributes;
    }

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

    @Override
    public String getProviderId() {
        return attributes.get("sub").toString();
    }

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

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


public class NaverResponse implements OAuth2Response{

    private final Map<String, Object> attributes;

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

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

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

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

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


public class CustomOauth2User implements OAuth2User {

    private final OAuth2Response oAuth2Response;

    private final String role;

    public CustomOauth2User(OAuth2Response oAuth2Response, String role) {
        this.oAuth2Response = oAuth2Response;
        this.role = role;
    }

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

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> collection = new ArrayList<>();
        collection.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return role;
            }
        });
        return collection;
    }

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

    public String getUserName(){
        return oAuth2Response.getProvider()+" "+oAuth2Response.getProviderId();
    }
}



@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final CustomerOauth2UserService customerOauth2UserService;

    public SecurityConfig(CustomerOauth2UserService customerOauth2UserService) {
        this.customerOauth2UserService = customerOauth2UserService;
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        http
                .csrf((csrf) -> csrf.disable());
        http
                .formLogin((login) -> login.disable());

        http
                .httpBasic((basic) -> basic.disable());

        http
                .oauth2Login((oauth2)-> oauth2
                        .userInfoEndpoint(userInfoEndpointConfig ->
                                userInfoEndpointConfig.userService(customerOauth2UserService)));

        http
                .authorizeHttpRequests((auth) -> auth
                        .requestMatchers("/", "/oauth2/**", "/login/**").permitAll()
                        .anyRequest().authenticated());

        return http.build();
    }
}

이 방식은 지금 내가 페이지를 직접 return하는데
프론트랑 협업을 할 때는 jwt를 반환하는 식으로 해야할거같다.

profile
답을 찾기 위해서 노력하는 사람

0개의 댓글