Facebook Javascript plugin과 spring security를 이용한 페이스북 로그인
web/Spring

Facebook Javascript plugin과 spring security를 이용한 페이스북 로그인

반응형

개인적으로 공부겸 만들고 있는 Wedul Pos에는 아이디와 패스워드를 사용해서 로그인하는 방식을 제공했다.

하지만 페이스북 로그인 방식을 추가해보고 싶어서 facebook 개발자 사이트에 가입하여 정보를 얻고 추가해봤다.

우선 페이스북 로그인 방식을 처리하는 방식은  Facebook Javascript plugin을 사용하여 spring security에서 인증을 하는 방식과 /sign/facebook 요청만 front에서 보내면 server에서 모든 처리를 진행하는 방식 두가지가 있다.

그 중에 첫번째 javascript plugin을 이용하는 방식을 사용해서 구현해보자.

1. facebook developer 사이트에서 javascript 내용 얻기
https://developers.facebook.com/docs/facebook-login/web#confirm 페이지에서 자바스크립트 플러그인에 대한 사용법과 소스를 받을 수 있다. App Id의 경우에는 개발자 사이트에 등록하면 받을 수 있다.

몇 가지 부분만 간단하게 설명을해보자.

※초기화
Facebook javascript 플러그인 사용을 위한 초기화.
{your-app-id}에는 발급받은 App Id를 version에는 최신 버전을 쓰면 된다. 지금은 v3.1이 최신이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  window.fbAsyncInit = function() {
    FB.init({
      appId      : '{your-app-id}',
      cookie     : true,  // enable cookies to allow the server to access 
                          // the session
      xfbml      : true,  // parse social plugins on this page
      version    : 'v2.8' // use graph api version 2.8
    });
 
    // Now that we've initialized the JavaScript SDK, we call 
    // FB.getLoginStatus().  This function gets the state of the
    // person visiting this page and can return one of three states to
    // the callback you provide.  They can be:
    //
    // 1. Logged into your app ('connected')
    // 2. Logged into Facebook, but not your app ('not_authorized')
    // 3. Not logged into Facebook and can't tell if they are logged into
    //    your app or not.
    //
    // These three cases are handled in the callback function.
 
    FB.getLoginStatus(function(response) {
      statusChangeCallback(response);
    });
 
  };
 
  // Load the SDK asynchronously
  (function(d, s, id) {
    var js, fjs = d.getElementsByTagName(s)[0];
    if (d.getElementById(id)) return;
    js = d.createElement(s); js.id = id;
    js.src = "https://connect.facebook.net/en_US/sdk.js";
    fjs.parentNode.insertBefore(js, fjs);
  }(document'script''facebook-jssdk'));
cs


※ 로그인 상태 체크

로그인 상태 체크를 위해 사용된다. 전달되는 response에는 현재 상태와 accessToken, appId등을 담고있다.

1
2
3
FB.getLoginStatus(function(response) {
    statusChangeCallback(response);
});
cs


1
2
3
4
5
6
7
8
9
10
11
// 상태값. 자세한 설명은 개발자 페이지 참고
{
    status: 'connected',
    authResponse: {
        accessToken: '...',
        expiresIn:'...',
        reauthorize_required_in:'...'
        signedRequest:'...',
        userID:'...'
    }
}
cs


 로그인 요청

로그인 요청 호출 스크립트이다.
같이 입력되어있는 scope에 경우에는 로그인시에 접근가능한 내용에 대한 권한 요청이다. 아래 내용에서 public profile에 대한 권한과 email 정보에 대한 권한을 요청한다.

1
2
3
FB.login(function(response) {
  // handle the response
}, {scope: 'public_profile,email'});
cs

로그인 요청 스크립트가 호출되면 다음과 같이 페이스북에서 제공하는 로그인 화면이 보여진다.


※로그아웃 요청

로그인 되어있는 사용자에 대해 로그아웃을 요청한다.
1
2
3
FB.logout(function(response) {
   // Person is now logged out
});
cs

단 로그아웃을 할때는 먼저 세션의 status를 확인하고 진행해야한다. 그렇지 않고 무작정 FB.logout을 통해 로그아웃을 시도하면 다음과 같은 오류가 발생한다.
FB.logout() called without an access token.

그래서 이런식으로 계정의 상태를 확인하고 진행하자.

1
2
3
4
5
6
7
8
9
10
11
12
// 페이스북 계정 로그아웃
var faceBookLogOut = function(callback) {
    FB.getLoginStatus(function(response) {
      if (response.status === 'connected') {
          FB.logout(function(response) {
              callback();
          });
      } else {
          callback();
      }
    });
};
cs


※ 사용자 정보 요청

로그인이 된 후에 현재 로그인된 사용자의 로그인 상태를 요청하는 스크립트이다.
response의 값은 {"name": "정철", "email" : "rokking1@naver.com", "userID" : "dkfdkfjalkd"} 와 같이 전달된다.

나는 로그인 후에 이 스크립트를 사용하여 전달받은 사용자 정보를 server로 전송하여 DB에 값을 저장하고 로그인 처리하였다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var loginFacebookLoginUserInfo = function() {
    // 로그인한 사용자의 정보 얻기
    FB.api('/me', {fields: 'name,email'},  function(response) {
        let param = {};
        param.snsId = response.id;
        param.nickname = response.name;
        param.email = response.email;
 
        // 사용자 소셜 로그인 요청
        Common.sendAjax({
            url: Common.getFullPath('user/login/facebook'),
            param,
            type: 'POST',
            success: () => {
                Common.pageMove('');
            },
            failed: () => {
                alert(Common.getMessage('user.login.message.checkAccount'));
            }
        });
    });
};
cs


2. Spring Security에서 로그인 처리하기.

1번 스크립트를 통해 페이스북 로그인을 하였다. 그리고 로그인이 성공한 뒤에 받은 사용자 정보를 wedul pos 서버에 전달하여 로그인 처리하였다.

※ 사용자 정보 전달 및 저장

로그인된 사용자 정보를 전달받고 DB에 값을 저장한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// UserController.java
 
/**
   * facebook으로 로그인
   *
   * @param reqDto the req dto
   * @return the response entity
   * @throws Exception the exception
*/
@RequestMapping("/login/facebook")
public ResponseEntity<?> loginfacebook(HttpServletRequest request, UserDto reqDto) throws Exception {
    return ResponseEntity.ok(userService.facebookLogin(request, reqDto));
}
 
// UserService.java (DB에 사용자 정보 저장)
private UserDto insertSnsUser(UserDto reqDto) throws Exception {
  UserDto userDto = selectUser(reqDto);
 
  if (null == userDto) {
    if (insertUser(reqDto)) {
        return reqDto;
    } else {
        return null;
    }
  }
 
  return userDto;
}
 
cs

그리고 Spring Security에 해당 사용자의 로그인 처리를 위해서 UsernamePasswordAuthenticationToken token을 생성하고 securityContext에 Autithentication을 적용해 주었다. 

여기서 삽질을 조금 했는데 securityContext에 Autithentication을 설정만 하면 되는줄 알았는데 그게 아니라 HttpSession에 "SPRING_SECURITY_CONTEXT" 속성에 securityContext를 넣어줘야했다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Override
public ResultDto facebookLogin(HttpServletRequest request, UserDto reqDto) throws Exception {
    UserDto userDto = insertSnsUser(reqDto);
 
    if (null == userDto) {
        return ResultDto.fail("등록된 사용자가 없습니다.");
    }
 
    // 인증 토큰 생성
    MyAuthenticaion token = new MyAuthenticaion(userDto.getSnsId(), "", Arrays.asList(new SimpleGrantedAuthority(Constant.ROLE_TYPE.ROLE_USER.toString())), userDto, EnumLoginType.FACE_BOOK);
    token.setDetails(new WebAuthenticationDetails(request));
    authProvider.authenticate(token);
 
    // Security Context에 인증 토큰 셋팅
    SecurityContext securityContext = SecurityContextHolder.getContext();
    securityContext.setAuthentication(token);
 
    // Create a new session and add the security context.
    HttpSession session = request.getSession(true);
    session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
 
    return ResultDto.success();
}
cs


자세한 소스코드는 Git을 참조.

https://github.com/weduls/wedulpos_boot

반응형