ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [flutter + firebase auth] 플러터 + 파이어베이스 로그인 연동 <네이버 로그인> part-8
    개발일지/flutter 2021. 1. 24. 19:00

    안녕하세요 개발하는 남자 개남입니다.

    드디어 파이어베이스 로그인 연동에 마지막 포스팅입니다.

    오늘 구현해볼 로그인은 네이버를 파이어베이스로 연동하는 포스팅입니다.


    지난 포스팅인 카카오 로그인을 잘 셋팅을 해놨다면 네이버 로그인은 식은 죽 먹기입니다:)

     

    [flutter + firebase auth] 플러터 + 파이어베이스 로그인 연동 <카카오 로그인> part-7

    안녕하세요 개발하는 남자 개남입니다. 오늘은 파이어 베이스로 카카오 로그인을 연동하는 포스팅을 진행하겠습니다. 혹시 Glitch 서버와 Firebase Admin이 세팅이 되시지 않았다면 이전 포스팅들을

    sudarlife.tistory.com

    이유라면 네이버 역시 로그인 프로세스가  Oauth2 프로토콜을 지원하기 때문입니다. 

    Oauth2 인증 프로세스에 대해 궁금하신 분들이 있다면??

    지난번 포스팅인 Oauth 2 인증 프로세스에 대해 다룬 포스팅을 보고 오시기 바랍니다.

     

    [flutter + firebase auth] 플러터 + 파이어베이스 로그인 연동 part-5

    안녕하세요 개발하는 남자 개남입니다. 지난 포스팅까지 구글/패북/애플 로그인을 구현하는 것을 모두 알아보았습니다. 이번 포스팅은 번외로 파이어 베이스에서 지원하지 않는 카카오 로그인

    sudarlife.tistory.com


    네이버 개발자 콘솔 설정

    자 이제 가장 먼저 네이버 개발자 콘솔로 접속해서 애플리케이션을 등록해주겠습니다.

     

    NAVER Developers

    네이버 오픈 API들을 활용해 개발자들이 다양한 애플리케이션을 개발할 수 있도록 API 가이드와 SDK를 제공합니다. 제공중인 오픈 API에는 네이버 로그인, 검색, 단축URL, 캡차를 비롯 기계번역, 음

    developers.naver.com

    애플리케이션 등록 버튼 클릭하여 등록 페이지로 이동해줍니다.

    프로젝트 이름 등록해주고 

    사용 API를 셀렉트 박스에서 [네아로 (네이버 아이디로 로그인)] 선택해줍니다.

    (여기서 네아로 가 뭘까? 생각했는데.... 줄임말이었다는 사실;; 이버 이디로 그인 ㅎㅎㅎㅎㅎ)

    아무튼 선택해주면 다음 화면처럼 추가가 되고 동의 항목을 설정하게 되어있습니다.

     

    이름 이메일 별명 프로필 사진까지 필수로 선택해줬습니다.

    필요한 항목이 있다면 정책에 맞게 선택해주시면 됩니다.

    적당히 선택하시고 하단부에 보시면 로그인 오픈 API 서비스 환경이라고 있습니다.

    모바일 웹을 선택해 줍니다.

     

    지금까지 함께 해오신 분들이라면?? 익숙한 화면이라고 생각되시죠? 

    서비스 URL에 저희가 만들고 있는 인증서버 (제 경우엔 Glitch 도메인이 될 것입니다.)  도메인을 넣어주시면 되고 

    Callback은 지난번 카카오 로그인처럼 auth와 token 2가지 등록해주시면 됩니다.

     

    아직 Glitch 서버에 받아줄 rest api를 등록해주지 않았기 때문에 잠시 멈추고 Glitch 서버로 이동해서 받아줄 api를 만들어 보겠습니다.

    app.get('/callbacks/naver/sign_in', async (request, response) => {
      //Authentication Code 받아 돌려줄 api
    })
    app.post('/callbacks/naver/token', async (request, response) => {
      //발급 받은 Naver AccessCode로 사용자 확인후 firebase 로 custom token 생성하기 위한 api
    })
    

     

    저는 다음과 같이 입력하였습니다.

     

    서비스 URL :

     - https://inconclusive-nasal-drawbridge.glitch.me 

    Callback URL 

     - https://inconclusive-nasal-drawbridge.glitch.me/callbacks/naver/sign_in

     - https://inconclusive-nasal-drawbridge.glitch.me/callbacks/naver/token

     

     

    네이버 개발센터에서 설정하는 부분은 완료되었습니다.


    Glitch 인증 서버(Node js)

     

    우선 Authorization_code 받아줄 api 먼저 작성하자면 아래 코드와 같이 하면 됩니다.

    app.get('/callbacks/naver/sign_in', async (request, response) => {
      const redirect = `webauthcallback://success?${new URLSearchParams(request.query).toString()}`;
      console.log(`Redirecting to ${redirect}`);
      response.redirect(307, redirect);
    })

    말 그대로 callbackUrlScheme을 통해 네이버 인증에서 보내준 Authorization_code를 앱으로 돌려주는 api 용도입니다.

    다음은 앱에서 발급받은 AccessToken을 전달받아 카카오 사용자 확인 후 Firebase Admin을 통해 token을 생성하는 api를 만들어 보겠습니다.

    app.post('/callbacks/naver/token', async (request, response) => {
      naver_auth.createFirebaseToken(request.body["accessToken"],(resulst)=>{
        response.send(resulst);
      });
    })

    이곳에서 naver_auth 부분은 별도의 naver_auth.js를 만들어서 상단에서 import를 시켜준 것입니다.

    const naver_auth = require('./naver_auth.js');

    naver_auth.js 파일에서는 총 3가지의 일을 합니다. ( 지난 카카오와 동일한 프로세스입니다. )

    첫 번째, accessToken으로 openapi.naver.com/v1/nid/me호출하여 정상적인 데이터를 불러올 수 있는지 확인

    (즉 변조된 토근인지 아닌지 확인하는 프로세스 진행 )

    두 번째, 받은 데이터를 토대로 Firebase Admin을 통해 Firebase에 사용자 생성 혹은 업데이트 

    세 번째, 생성된 사용자의 uid를 토대로 CustomToken 생성 

     

    여기서 사용된 naver_auth.js 는 지난 kakao_auth.js 파일을 몇 가지만 변경하고 동일하게 사용하였습니다.

    소스를 작업하면서 확인한 문서는 네이버 공식문서를 참조하면서 작성하였습니다.

     

    전체 소스는 다음과 같습니다.

    'use strict'
    
    const admin = require('./firebase_admin.js');
    const Async = require('async');
    const axios = require('axios');
    
    
    const naverRequestMeUrl = 'https://openapi.naver.com/v1/nid/me'
    
    function requestMe(naverAccessToken,callback) {
      console.log('Requesting user profile from Naver API server. '+ naverAccessToken)
      return axios.get(naverRequestMeUrl,{
        method: 'GET',
        headers: {'Authorization': 'Bearer ' + naverAccessToken}
      }).then((result)=>{
        callback(null,result.data,result);
      });
    }
    
    
    function updateOrCreateUser(userId, email, displayName, photoURL) {
      console.log('updating or creating a firebase user');
      const updateParams = {
        provider: 'NAVER',
        displayName: displayName,
      };
      if (displayName) {
        updateParams['displayName'] = displayName;
      } else {
        updateParams['displayName'] = email;
      }
      if (photoURL) {
        updateParams['photoURL'] = photoURL;
      }
      console.log(updateParams);
      return admin.auth().updateUser(userId, updateParams).then(function(userRecord) {
        // See the UserRecord reference doc for the contents of `userRecord`.
        console.log("Successfully updated user", userRecord.toJSON());
        userRecord['uid'] = userId;
        if (email) {
          userRecord['email'] = email;
        }
        return admin.auth().createUser(userRecord);
      });
    }
    
    
    function createFirebaseToken(naverAccessToken,callback) {
    
      Async.waterfall([
        (next)=>{
          requestMe(naverAccessToken,(error,response,boy)=>{
            console.log(response)
            const body =response.response // JSON.parse(response)
            console.log(body)
            const userId = `naver:${body.id}`
            if (!userId) {
              return response.status(404)
              .send({message: 'There was no user with the given access token.'})
            }
            let nickname = null
    
            const updateParams = {
              uid :userId,
              email :body.email,
              provider: 'NAVER',
              displayName: '',
            };
            if (body.nickname) {
              updateParams['displayName'] = body.nickname;
            } else {
              updateParams['displayName'] = body.email;
            }
            if (body.profile_image) {
              updateParams['photoURL'] = body.profile_image;
            }
    
            next(null,updateParams)
          });
        },
        (userRecord, next) => {
          console.log(userRecord.email);
          admin.auth().getUserByEmail(userRecord.email).then((userRecord)=>{
            next(null,userRecord);
          }).catch((error)=>{
            console.log(error);
            admin.auth().createUser(userRecord).then((user)=>{
              next(null,user)
            })
          })
        },
        (userRecord, next) => {
          console.log(userRecord);
          console.log("**************");
          const userId = userRecord.uid
          console.log(`creating a custom firebase token based on uid ${userId}`)
          admin.auth().createCustomToken(userId, {provider: 'NAVER'}).then((result)=>{
            console.log(result);  
            next(null , result);
          });
        }
      ],(err, results) => {
          console.log(results)
          callback(results);
      });
    
    }
    
    module.exports={
      createFirebaseToken
    }

    자 이제 모든 설정은 끝이 났습니다.

    이제 클라이언트 앱에서 작업하러 프로젝트 소스로 이동해보겠습니다.


    프로젝트 소스 관리

     

    지난번 카카오 로그인을 설정하신 분이라면 별도의 설정 없이 바로 소스 코드 작성만으로 네이버 로그인을 구현할 수 있습니다.

    login.dart. 파일에 카카오 로그인 버튼을 추가해주겠습니다.

    FlatButton(
      color: Colors.grey.withOpacity(0.3),
      onPressed: signInWithNaver,
      child: Text("Naver Login"),
    ),

    onPressed 클릭 시 로그인 프로세스를 진행할 signInWithNaver 로직을 아래와 같이 작성합니다.

    Future<UserCredential> signInWithNaver() async {
        final clientState = Uuid().v4();
        final url = Uri.https('nid.naver.com', '/oauth2.0/authorize', {
          'response_type': 'code',
          'client_id': "<네이버에서 제공하는 Client_id 입력>",
          'redirect_uri':
              '<네이버에 등록한 authrization_code 받을 return uri 입력>',
          'state': clientState,
        });
    
        final result = await FlutterWebAuth.authenticate(
            url: url.toString(),
            callbackUrlScheme: "webauthcallback");
        final body = Uri.parse(result).queryParameters;
    
        final tokenUrl = Uri.https('nid.naver.com', '/oauth2.0/token', {
          'grant_type': 'authorization_code',
          'client_id': "<네이버에서 제공하는 Client_id 입력>",
          'client_secret': "<네이버에서 제공하는 Client Secret 입력>",
          'code': body["code"],
          'state': clientState,
        });
        var responseTokens = await http.post(tokenUrl.toString());
        Map<String, dynamic> bodys = json.decode(responseTokens.body);
        var response = await http.post(
            "https://sage-dorian-anise.glitch.me/callbacks/naver/token",
            body: {"accessToken": bodys['access_token']});
        return FirebaseAuth.instance.signInWithCustomToken(response.body);
    }	

    이제 안드로이드 / iOS 로그인 시도해보시면 로그인이 정상적으로 진행되실 것입니다.


    이렇게 해서 플러터 환경에서 파이어베이스 sns 로그인에 대해서 포스팅을 마쳤습니다.

    전체적인 내용을 제 개인 youtube에서 영상으로 다시 확인하실 수 있습니다.

    감사합니다~!

    댓글

Designed by Tistory.