brunch

You can make anything
by writing

C.S.Lewis

by 갱그리 May 17. 2016

Spring 소셜로그인(2)
spring-social

5/17 개발일기

Spring 소셜로그인(1) security 이해 - https://brunch.co.kr/@ourlove/67 에서 이어집니다.


SpringSocial 을 구현할 때, 대부분 SocialConfigurerAdapter 를 상속하여 SocialConfig를 구현한다. 먼저 여기에서 Override 해야 하는 Method에 대해 먼저 하나하나 살펴보려고 한다.


addConnectionFactories


말그대로 ConnectionFactory 를 추가하는 메소드다. 내가 연결하고 싶은 소셜의 ConnectionFactory 를 여기에 지정하고, 키값과 secret 키를 여기에서 넘겨준다.


application.properties

google.clientId = {google-client-id}
google.clientSecret = {google-client-secret}


SocialConfig

@Override
    public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig, Environment env) {
        cfConfig.addConnectionFactory(new GoogleConnectionFactory(
                env.getProperty("google.clientId"),
                env.getProperty("google.clientSecret")));
    }


그런데 spring-social-facebook api 를 import 한 경우, facebook ConnectionFactory는 따로 작성하지 않아도 된다. (아니, 따로 작성하지 않아야 한다. 여기에 FacebookConnectionFactory 를 add 하면 중복 등록이라고 오류 난다) 왜냐하면, spring-social-facebook api 안에서 이미 facebookConnectionFactory 를 구현해놓았기 때문이다. 


사실 이 때문에 Facebook 은 SocialConfig를 별도로 지정해줄 필요가 없었다.

SocialConfig 작성 없이 페이스북 Social Login 을 구현한 예제는 앞선 포스팅에서 설명해두었다. 



getUserIdSource


이 메소드는 UserIdSource 를 리턴한다. 그리고 UserIdSource 를 따라가보면 아래와 같이 구현되어 있는 인터페이스임을 알 수 있다. 

public interface UserIdSource {
/**
 * @return an account ID.
 */
String getUserId();
}

어렵게 생각할 것 없다. 그냥 UserId를 리턴하는 인터페이스다. 그러니 getUserIdSource는 어디서 UserId를 갖고 와서 리턴해주면 되는 지 설정해달라는 메소드이다. 나는 아래와 같이 설정했다. 

@Override
    public UserIdSource getUserIdSource() {
        return new AuthenticationNameUserIdSource();
    }

new AuthenticationNameUserIdSource() 를 따라가보면, 이러한 메소드가 나온다. 여기에서는 이전 포스팅에서 봤었던 SecurityContextHolder가 등장한다. 우리는 앞서 로그인 한 유저를 UserDetails 객체로 담아서, Authentication 으로 인증시켜 준 후에 SecurityContext로 넣어주는 프로세스를 알고 있다.  

public class AuthenticationNameUserIdSource implements UserIdSource {

public String getUserId() {
    Authentication authentication =                                             SecurityContextHolder.getContext().getAuthentication();
   if (authentication == null) {
            throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
    }
    return authentication.getName();
    }
}

우리가 최초 로그인할 때 생성했던 UserDetails 객체를 저장한 내용과 동일하다. 그러니까 이렇게 설정해두게 되면, 최초 로그인할 때 반드시 SecurityContextHolder 를 통해 SecurityContext에 인증된 User 정보를 담아두어야 하는 것이다. 정리하자면 이 메소드는 이런 이야기다.


- "connection 한 이후에 provider랑 또 연결해야하면 나는 UserId를 어디서 갖고 오면 되니?"

- "최초 로그인할 때 SecurityContext 에 담아줄테니 그 이후에는 거기서 가져가 쓰렴"



getUsersConnectionRepository 


한번 provider와 커넥션을 맺고나면 connection 들은 유저 단위로 connectionRepository 라는 곳에 저장된다. 여기에서는 connectionRepository 를 어디에 저장할 것인지 설정할 수 있다. "어디에" 저장하냐는 문제는 매우 중요한데, 어디에 저장하느냐에 따라 connection 이 얼마나 지속되는 지를 결정할 수 있기 때문이다. 


디폴트 셋팅은 inmemroy 지만, jdbc-based repository 도 제공한다. 이 이야기인즉슨 RDBMS 와 연결이 되어 있는 동안 내내 user의 Connection 을 유지시켜 줄 수 있다는 뜻. 예제도 jdbcUserRepository 를 채택하고 있어서 나도 그걸로 그냥 따라했다. 


 @Override
    public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
        JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(datasource, connectionFactoryLocator, Encryptors.noOpText());
        return repository;
}



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