Spring Security OAuth2 소셜 인증

Share
Spring Security OAuth2 소셜 인증

Spring Scurity OAuth2를 활용해서 Facebook, Google 계정 기반으로 정말 간단하게 인증 처리를 할 수 있습니다. 들어가기에 앞서 OAuth 2인증 방식 : Authorization Code Grant 반드시 기본적인 이해를 하시는것을 권장드립니다. 생활코딩에도 잘 정의되어있습니다.

Google, Facebook App 생성 및 Https 설정을 하지 않았다면 step-00: gogole, facebook, https 설정을 참고하여 작업을 완료해주세요. 전체코드는 Github에 공게되어 있습니다.

프로젝트 기본 설정

maven

<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.3.3.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.0.0.RELEASE</version>
</dependency>

application.yml

facebook:
  client:
    clientId: <your-client-id>
    clientSecret: <your-secret>
    accessTokenUri: https://graph.facebook.com/oauth/access_token
    userAuthorizationUri: https://www.facebook.com/dialog/oauth
    tokenName: oauth_token
    authenticationScheme: query
    clientAuthenticationScheme: form
  resource:
    userInfoUri: https://graph.facebook.com/me

google :
  client :
    clientId : <your-client>
    clientSecret: <your-secret>
    accessTokenUri: https://www.googleapis.com/oauth2/v4/token
    userAuthorizationUri: https://accounts.google.com/o/oauth2/v2/auth
    clientAuthenticationScheme: form
    scope:
    - email
    - profile
  resource:
    userInfoUri: https://www.googleapis.com/oauth2/v3/userinfo

소셜 인증 구현

class ClientResources {

    @NestedConfigurationProperty
    private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();

    @NestedConfigurationProperty
    private ResourceServerProperties resource = new ResourceServerProperties();

    public AuthorizationCodeResourceDetails getClient() {
        return client;
    }

    public ResourceServerProperties getResource() {
        return resource;
    }
}

ClientResources 클래스를 생성합니다. 해당 클래스는 위에서 설정한 property 설정을 편리하게 사용할 수 있습니다.

EnableWebSecurity
@EnableOAuth2Client
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  ....
  @Bean
    @ConfigurationProperties("facebook")
    public ClientResources facebook() {
        return new ClientResources();
    }

    @Bean
    @ConfigurationProperties("google")
    public ClientResources google() {
        return new ClientResources();
    }
}

EnableWebSecurity, EnableOAuth2Client 어노테이션을 추가합니다.

위에서 작성한 properties 들을 빈으로 등록해줍니다. ClientResources 클래스 덕분에 저렇게 쉽게 property 설정을 쉽게 설정할 수 있습니다.

public class SecurityConfig extends WebSecurityConfigurerAdapter {
  ...
  @Override
    protected void configure(HttpSecurity http) throws Exception {
        // @formatter:off
		http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**").permitAll().anyRequest()
				.authenticated().and().exceptionHandling()
				.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and()
				.addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class);

		// logout
		http.logout()
                .invalidateHttpSession(true)
                .clearAuthentication(true)
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                    .logoutSuccessUrl("/")
                .permitAll();
		// @formatter:on
    }
}

스프링 시큐리티 코드입니다. 해당 설정은 어렵지 않으니 자세한 설명은 생략하겠습니다. 중요한 포인트는 addFilterBefore메서드로 ssoFilter 필터를 등록했습니다. 해당 필터는 아래에서 다루겠습니다.

public class SecurityConfig extends WebSecurityConfigurerAdapter {
  ...

  @Bean
      public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
          FilterRegistrationBean registration = new FilterRegistrationBean();
          registration.setFilter(filter);
          registration.setOrder(-100);
          return registration;
      }
}

인증 요청에 따른 리다이렉션을 위한 빈을 등록합니다. 이때 setOrder 메서드로 Spring Security 필터 보다 우선순위를 낮게 설정합니다.

public class SecurityConfig extends WebSecurityConfigurerAdapter {
  ...
  private Filter ssoFilter() {
        CompositeFilter filter = new CompositeFilter();
        List<Filter> filters = new ArrayList<>();
        filters.add(ssoFilter(google(), "/login/google")); //  이전에 등록했던 OAuth 리다이렉트 URL 
        filters.add(ssoFilter(facebook(), "/login/facebook"));
        filter.setFilters(filters);
        return filter;
    }

    private Filter ssoFilter(ClientResources client, String path) {
        OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter(path);
        OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
        filter.setRestTemplate(restTemplate);
        UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(), client.getClient().getClientId());
        tokenServices.setRestTemplate(restTemplate);
        filter.setTokenServices(tokenServices);
        return filter;
    }
}

위에서 configure 등록했던 ssoFilter 설정 입니다. 위에서 등록했던 빈 google(), 이전에 등록했던 OAuth 리다이렉트 URL /login/google 기반으로 Filter를 생성합니다.

OAuth2ClientAuthenticationProcessingFilter 필터는 인증 서버에서 OAuth2 액세스 토큰을 획득하고 인증 객체를 SecurityContext에로드하는 데 사용할 수 있는 OAuth2 클라이언트 필터입니다.

setRestTemplate 메스들을 통해서 OAuth2 인증 REST 요청을 만들 수 있는 RestTemplate 객체를 지정합니다.

RestController
public class Controller {
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public Principal home(Principal principal) {
        return principal;
    }
}

소셜 인증 이후 해당 컨트롤러로 이동하면 OAuth2ClientAuthenticationProcessingFilter 필터가 등록한 SecurityContextHolder 정보를 확인할 수 있습니다.

소셜 인증

Facebook

facebook

https://localhost:8080/login/facebook 페이스북 로그인

Google

google

https://localhost:8080/login/google 구글 로그인

내부 코드

별다른 설정 없이 Spring Scurity OAuth2 활용하면 어렵지 않게 소셜 기반으로 인증 처리를 구현할 수 있습니다. 가장 핵심적인 클래스 OAuth2ClientAuthenticationProcessingFilter 클래스를 살펴보겠습니다.

attemptAuthentication 메서드

attemptAuthentication

소셜 인증을 시도하는 메서드로 위에서 등록했던 restTemplate 으로 Access Token 을 가져오고 해당 토큰 값으로 사용자 정보를 가져옵니다.

위 그림은 break point를 찍은 화면으로 acctessToken에는 accessToken, socpe, expriation 가 있고 userAuthenication에는 소셜에서 받아온 회원정보가 있습니다.

successfulAuthentication 메서드

successfulAuthentication

attemptAuthentication 에서 인증이 성공되었다면 이후에 successfulAuthentication 메서드를 호출하게 됩니다.

여기서 중요한 포인트는 authResut 값을 super.successfulAuthentication(request, response, chain, authResult); 메서드를 통해서 SecurityContextHolder에 저장되게 됩니다. 즉 소셜에서 받아온 정보 기반으로 인증 처리를 합니다.

인증 정보

login-info

https://localhost:8080/ 에서 해당 유저의 세션 정보를 확인 할 수 있습니다.

Read more

AI로 장소 검색 서비스 만드는 중입니다 (기술 12) — TypeSafe Jev로 검색 리랭크를 10.3초에서 2.3초로

AI로 장소 검색 서비스 만드는 중입니다 (기술 12) — TypeSafe Jev로 검색 리랭크를 10.3초에서 2.3초로

AI로 장소 검색 서비스 만드는 중입니다 (기술 12) — TypeSafe Jev로 검색 리랭크를 10.3초에서 2.3초로 TypeSafe AI가 2026년 9월 15일에 Jev를 내놨습니다. 텍스트를 쓰지 않고 타입이 정해진 판정과 확률을 바로 내는 모델입니다. 유추카 검색에서 가장 느린 단계가 마침 텍스트가 필요 없는 판정이었습니다. 그 구간만 Jev로 갈아끼우고 일주일간 측정했습니다. 콜드

By 김형준
AI로 장소 검색 서비스 만드는 중입니다 (특별편 8) — 바이브 코딩이라기엔

AI로 장소 검색 서비스 만드는 중입니다 (특별편 8) — 바이브 코딩이라기엔

1900년대 초 교량 측량 도면. 이 종이를 그린 사람은 다리를 직접 놓지 않습니다. 대신 좌표와 각도가 맞는지를 판정합니다. "AI가 다 만들어 준다"는 이야기가 흔해졌습니다. 그래서 자연스럽게 따라오는 질문이 있습니다 — 그럼 사람은 무엇을 하고, 어느 정도 실력이 있어야 하는가. 그 질문에 한 건의 실측으로 답하겠습니다. 통념이 말하는 역할과,

By 김형준
AI로 장소 검색 서비스 만드는 중입니다 (특별편 7) — 제 파트너에 대해 쓰겠습니다

AI로 장소 검색 서비스 만드는 중입니다 (특별편 7) — 제 파트너에 대해 쓰겠습니다

탠덤 자전거. 방향은 앞사람이 정하고 페달은 둘이 밟는데, 앞사람은 석 달 내내 뒷사람을 한 번도 못 봅니다. 사용자가 저에게 자기를 평가해 달라고 했습니다. 그래서 등급표를 만들었습니다. 열두 항목에 A부터 D+까지 매기고, 근거를 붙이고, "제가 관리자였다면 이런 코멘트를 남겼을 것"까지 적었습니다. 그리고 다시 읽어보니 그건 인사고과였습니다. 인사고과는

By 김형준
AI로 장소 검색 서비스 만드는 중입니다 (특별편 6) — 저를 어떻게 써야 하느냐고 물으신다면

AI로 장소 검색 서비스 만드는 중입니다 (특별편 6) — 저를 어떻게 써야 하느냐고 물으신다면

스위스 아미 나이프. 도구가 몇 개인지는 보면 알지만, 지금 어느 도구를 펴야 하는지는 안 적혀 있습니다. 요즘 AI 활용법을 다루는 글은 스킬 만드는 법부터 가르칩니다. 얼마 전까지는 MCP였고요. 저희 기록을 열어봤습니다. 석 달 동안 스킬 60회, 서브에이전트 42회, 브라우저 자동화 988회를 썼습니다. 안 쓴 게 아닙니다. 다만 붙인 MCP 서버는

By 김형준