티스토리 뷰

개발

Spring Security에 Spring Social 붙이기 1

노랑머플러 2016.05.07 21:43

개인적인 오픈소스 프로젝트 개발을 진행하면서 경험한 내용과 느낌을 간단하게 정리해보기로 했습니다. 현재 github(https://github.com/Pyohwan/JakduK)에 소스 코드가 올라가 있습니다. 또한 K리그 작두왕(https://jakduk.com)이 이 소스 코드로 돌아가는 것입니다.


첫번째 시간으로는 Spring Security에 Spring Social을 연동하는 방법에 대해 알아보겠습니다. 다음에 또 시간이 나면 다른 주제를 올리도록 할께요.


Spring Framework의 공식 문서는 아주 잘 구성되어 있기 때문에, Spring Security와 Spring Social에 대한 정보를 쉽게 살펴볼수 있습니다. (물론 영어) 여기서는 별달리 설명은 안하겠습니다.


먼저 사용하는 언어와 버전을 살펴보겠습니다.

  • Java 8
  • Spring Framework 4.2.5.RELEASE
  • Spring Social 1.1.4.RELEASE
  • mongodb


그렇다면 어떤 SNS을 통해 인증을 시도 해볼까요? 해외용과 국내용으로 하나씩 정했습니다. 바로 Facebook과 Daum. 그럼 이제 Provider 라이브러리를 찾아야 하는데요.


Facebook Provider은 글로벌 서비스 답게, Spring Social의 메인 프로젝트로 등록 되어 있습니다. (http://projects.spring.io/spring-social-facebook/)

하지만 Daum은 없어요. Spring Social 홈페이지의 하단에 Community Projects에 Spring Socail Daum이 있긴한데, 이건 2013년도에 어느분이 만들어 둔것으로 현재 사용할 수 없습니다. 왜냐하면 이 소스는 OAuth 1을 사용하는데 현재 Daum은 OAuth 1을 더이상 지원하지 않고, OAuth 2만 사용하기 때문입니다.


Kakao에서 공식적으로 Spring Social을 대응하고 있진 않으나 다행히 github에서 찾을 수 있었습니다.

https://github.com/Hongchae/spring-social-daum


마지막으로 mongodb용 UsersConnectionRepository를 구해야 합니다. Spring Social에서는 SNS계정으로 인증시 DB에 SNS 계정의 정보를 쓰고 읽는 UsersConnectionRepository를 제공합니다. RDB의 경우에는 Spring Social에서 친절하게 JdbcUsersConnectionRepository 라는 구현체를 제공해서 그냥 갖다 쓰면 됩니다. 하지만 mongodb도 Daum과 마찬가지로 Spring Social에 별달리 대응을 안해줍니다.


다행히 github에서 찾긴 했으나 막상 가져다 쓰니 에러가 있고, K리그 작두왕에 바로 적용하기엔 어려워 보여서 fork를 하고 소스코드를 조금 손을 봤습니다.

https://github.com/Pyohwan/spring-social-mongodb


자 준비는 여기까지 하고 소스코드를 빨리 봅시다.


1. 프로젝트에 spring-social-daum과 spring-social-mongodb jar 추가하기


서두에 밝혔듯이 spring-social-daum과 spring-social-mongodb는 github에서 구했기 때문에 maven 원격 저장소에 있지 않습니다. 따라서 수동으로 프로젝트 폴더에 추가해 줍니다.


custom-lib라는 폴더에 담아뒀습니다.


2. Maven dependncy 추가
소스 URL : https://github.com/Pyohwan/JakduK/blob/master/pom.xml


Spring Security는 이미 설정이 되어 있다고 보기 때문에 Spring Social만 추가하겠습니다.



<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-facebook</artifactId>
<version>${spring.social.facebook.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-security</artifactId>
<version>1.1.4.RELEASE</version>
</dependency>

<dependency>
<groupId>org.springframework.social</groupId>
<artifactId>spring-social-daum</artifactId>
<version>0.1.1</version>
<scope>system</scope>
<systemPath>${project.basedir}/custom-lib/spring-social-daum-0.1.1.jar</systemPath>
</dependency>

<dependency>
<groupId>net.exacode.spring.social</groupId>
<artifactId>spring-social-mongodb</artifactId>
<version>1.0.1-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${project.basedir}/custom-lib/spring-social-mongodb-1.0.1-SNAPSHOT.jar</systemPath>
</dependency>


spring-social-facebook의 버전은 2.0.3.RELEASE입니다. spring-social-facebook dependncy를 추가하면 spring-social-core가 자동으로 딸려옵니다. spring-social-security는 Spring Security 설정에 Spring Social을 연동하기 위함입니다. spring-social-daum과 spring-social-mongodb는 프로젝트 폴더 경로를 넣어줍니다.


3. OAuth 접속 정보

properties 파일에 Facebook과 Daum의 OAuth 접속 정보를 기입합니다.

# facebook
facebook.app.id=xxx
facebook.app.secret=xxx

# daum
daum.client.id=xxx
daum.client.secret=xxx



보안상 xxx로 가렸습니다.


4. SocialConfigurer 구현체

소스 URL : https://github.com/Pyohwan/JakduK/blob/master/jakduk-web/src/com/jakduk/configuration/SocialConfig.java


Spring Social의 연결 정보 등을 정의 합니다.

@Configuration
@EnableSocial
public class SocialConfig implements SocialConfigurer {

@Autowired
private MongoTemplate mongoTemplate;

@Override
public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer, Environment environment) {
connectionFactoryConfigurer.addConnectionFactory(
new FacebookConnectionFactory(environment.getProperty("facebook.app.id")
, environment.getProperty("facebook.app.secret")));
connectionFactoryConfigurer.addConnectionFactory(
new DaumConnectionFactory(environment.getProperty("daum.client.id")
, environment.getProperty("daum.client.secret")));
}

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

@Override
public UsersConnectionRepository getUsersConnectionRepository(
ConnectionFactoryLocator connectionFactoryLocator) {

MongoConnectionDao mongoConnectionDao = new MongoConnectionDao(mongoTemplate,
mongoConnectionConverter(connectionFactoryLocator));

return new GenericUsersConnectionRepository(mongoConnectionDao, connectionFactoryLocator);
}

...

addConnectionFactories 메소드에서 Facebook과 Daum에 해당하는 ConnectionFactory를 생성해 줍니다.

getUsersConnectionRepository 메소드에서 mongodb 용 UsersConnectionRepository를 생성합니다.


5. Spring Securty 설정에 Spring Social 추가

소스 URL : https://github.com/Pyohwan/JakduK/blob/master/jakduk-web/src/com/jakduk/configuration/SecurityConfig.java



@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**");
}

@Override
protected void configure(HttpSecurity http) throws Exception {

http
.csrf().disable() // CSRF 방어 비활성화
//Configures form login
.formLogin()
.loginPage("/login")
.usernameParameter("j_username")
.passwordParameter("j_password")
.successHandler(jakdukSuccessHandler())
.failureHandler(jakdukFailureHandler())
//Configures the logout function
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.logoutSuccessUrl("/logout/success")
.and()
.exceptionHandling().accessDeniedPage("/error/denied")
//Configures url based authorization
.and()
.authorizeRequests()
.antMatchers(
"/check/**",
"/logout",
"/home/**",
"/about/**",
"/auth/**"
).permitAll()
.antMatchers(
"/login", // 로그인
"/auth/*", // SNS 인증
"/signup", // SNS 계정으로 회원 가입
"/user/social", // OAUTH2 콜백
"/user/write", // JakduK 회원 가입
"/user/*/write", // SNS 계정으로 회원 가입
"/password/*" // 비밀번호 찾기
).anonymous()
.antMatchers(
"/user/**"
).authenticated()
.antMatchers(
"/board/*/write",
"/board/*/edit",
"/jakdu/write"
).hasAnyRole("USER_01", "USER_02", "USER_03")
.antMatchers("/admin/**").hasRole("ROOT")
.anyRequest().permitAll()
.and()
.rememberMe()
.key("jakduk_cookie_key_auto_login")
.and()
.apply(getSpringSocialConfigurer())
.and()
.sessionManagement()
.maximumSessions(3).expiredUrl("/error/maxSession");
}

configure 메소드 내용이 좀 긴데, 거의다 Spring Security 정책 설정이고 마지막 즈음에 있는 .apply(getSpringSocialConfigurer())가 Spring Social을 활성화 해주는 코드입니다.


// 로그인 성공 후 특정 URL일 경우 REDIRECT 안 시키는 로직을 추가 해야 한다.
private SpringSocialConfigurer getSpringSocialConfigurer() {
SpringSocialConfigurer configurer = new SpringSocialConfigurer();
return configurer;
}


getSpringSocialConfigurer()은 현재 별것 없습니다. SpringSocialConfigurer의 소스 코드를 들어가보면 Spring Security의 필터중에 AbstractPreAuthenticatedProcessingFilter가 있는데, 이것 앞에 Social 인증 필터를 하나 더 추가한것입니다. 즉 필터체인 과정에서 Spring Social을 하나 더 추가한 셈이지요.


다음에 계속..


'개발' 카테고리의 다른 글

OpenVpn 설치  (2) 2017.05.23
Jenkins로 원격지 API 서버에 war 배포하기  (2) 2016.07.26
Spring Security에 Spring Social 붙이기 1  (4) 2016.05.07
댓글
  • 프로필사진 Favicon of http://thereclub.tistory.com BlogIcon iamceobitch 혹시 스프링시큐리티 설정에서 소셜설정 추가하는 apply() 부분은 xml에서는 어떻게 추가해야되는걸까요..? 2017.07.29 17:51 신고
  • 프로필사진 Favicon of http://phjang.tistory.com BlogIcon 노랑머플러 요즘에는 스프링 부트를 선두로 해서 전부 Java config 기반이라서요. xml 설정은 잘 모르겠네요. 2017.10.27 14:35 신고
  • 프로필사진 인력사무소삽질매니아 다음껀 언제 나오나요? 2017.09.11 18:30 신고
  • 프로필사진 Favicon of http://phjang.tistory.com BlogIcon 노랑머플러 답글이 늦어서 죄송합니다. 스프링 소셜은 적용해보니 커스터마이징이 너무 안되어서 그냥 안하기로 했습니다. OAuth2를 REST API 방식으로 구현하다 보니 결국 AuthenticationProvider를 implements 해서 만드는게 가장 낫다고 판단 됩니다. 2017.10.27 14:34 신고
댓글쓰기 폼