brunch

You can make anything
by writing

C.S.Lewis

by 갱그리 May 17. 2016

Spring 소셜로그인(1)
- security 이해

5/13 개발일기

페이스북 연동은 지난 번에 했었지만, 해놓고도 이해가 안가는 예제였다. connectionFactory 를 따로 생성하지 않아도 된다니.. 그런데 구글은 따로 생성해야 하고.. 으잉?-_- 이해가 너무 안가서 다른 예제를 찾아봤다. 내 개발 요구조건은 이랬다.


1. 구글/페이스북/네이버 소셜 로그인 연동 (네이버는 나중에..)

2. 자체 이메일로도 로그인/회원가입이 될 것

3. DB에 저장이 되어야 함


많은 예제를 뒤지고 적용하고 실패하고 .. 반복하다가, 결국 아래 예제를 따라하면서 성공했다. 


위 예제에 샘플 코드는 잘 나와있으니.. 스프링 부트 완전 초심자의 입장에서 소셜 로그인에 대한 시행착오 끝에 배워나간 것들을 적어본다.


1. Spring-security 와 SecurityContext


소셜로그인이고 자시고 간에 일단 "로그인"을 하는 만큼 Spring security 를 빼놓을 수 없다. 아니.. 빼놓을 수 없는 정도가 아니라, 사실 소셜로그인을 구현하는 대부분의 코드가 Spring security 에 의한 것이다.  SecurityConfig 기본 설정을 보면 단순히 접근 Url 정도나 컨트롤하는 것 같지만, 그렇지 않다.. 사실 여기엔 많은 것이 숨겨져 있다. 


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable() -> csrf 차단 해제
                .anonymous()
            .and()
                .formLogin() 
                .loginPage("/login")  -> 로그인 페이지 지정
                .defaultSuccessUrl("/", true) ->로그인 성공 후 리다이렉트할 URL
                .loginProcessingUrl("/login/authenticate") ->
                .failureHandler(new CustomLoginFailureHandler()) ->로그인실패시
            .and()
                .logout() -> 로그아웃할때
                .deleteCookies("SESSION") -> session 명의 쿠키 날려줘
                .logoutUrl("/logout") -> 로그아웃url 정의
                .logoutSuccessUrl("/login") -> 로그아웃 성공 후 리다이렉트할 URL
            .and()
                .authorizeRequests()
                .antMatchers(
                        "/webjars/**",
                        "/resources/**",
                        "/",
                        "/auth/**",
                        "/login",
                        "/error",
                        "/signup"
                ).permitAll()   ->위에 지정된 url 패턴은 익명 유저도 permit
                .antMatchers("/**").hasRole("USER")
            .and()
                .apply(new SpringSocialConfigurer()); ->social 로그인할꺼야
    }


여기서 SecurityContext를 알아야 한다. SecurityContext는 인증된 유저 정보를 담아, 웹 어플리케이션 어디서든 유저 정보에 접근할 수 있도록 돕는다. 그리고 SecurityContext에 전달할 "인증된 유저 정보"는 UserDetails 객체로 전달한다. 


프로세스를 정리해보면 이렇다.

(1) 사용자 로그인
(2) 폼에서 사용자 정보를 받아 UserDetailsService에 전달
(3) 전달받은 정보로 UserDetails 객체를 생성
(4) 해당 객체를 Authentication 에 전달하여 인증함
(5) 인증한 정보를 SecurityContext에 전달하여 "인증된 유저"로 정의함
(6) jsp에서 인증된 사용자 정보에 접근할 때 SecurityContext를 사용함


그리고 이 프로세스 중 (3)~(5)는 위 예제를 따를 때, 아래와 같은 로직으로 구현된다.

public void AuthUser(User user){
       FrontUserDetail frontUserDetail = new FrontUserDetail(user);
        Authentication authentication = new UsernamePasswordAuthenticationToken(frontUserDetail, null, frontUserDetail.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);    
}


저 예제에서는 User와 UserDetails 두가지 객체가 등장한다. 나는 이 부분에 좀 헷갈렸다. 정리해보면,

User 객체는 일종의 DAO<->DB 통신간 필요한 Data Entity 였다면

UserDetails는 Spring security 에 기반하여 "인증된 사용자" 를 만들기 위한 객체였다.


그러면 이때 인증된 사용자 정보를 담은 SecurityContext는 언제 초기화될까? 여기에서 SecurityConfig의 logout 부분 설정을 보면 된다. 보통 같으면 직접 세션 날리고 이런걸 구현해줬겠지만, SecurityConfig에 logout URL을 지정하면, 사용자가 저 URL에 접근할 때 알아서 다 날려준다.. SecurityContext가 초기화되고, 그리고 deleteCookies("SESSION") 이렇게 정의하면 내가 따로 구현한 SESSION 도 함께 초기화된다. 완전 편하다..


브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari