[Flutter] 네이버, 카카오 Social Login 구현 (2. 네이버 로그인 구현)

2021-04-03

이번에는 Flutter로 네이버 Social Login을 구현해 볼 것이다. 서버 설정을 하지 않았다면 아래 링크를 먼저 보고 오자.

[Flutter] 네이버, 카카오 Social Login 구현 (1. 서버 설정)


네이버 설정

네이버 아이디로 로그인 홈페이지로 가서 오픈 API 이용 신청을 한다.


1

원하는 애플리케이션 이름을 입력하고 제공 정보를 선택한다. 그리고 아래에서 환경 추가에서 Mobile 웹을 선택하면 새로운 입력 공간이 나온다.


2

여기서 서비스 URL에 REST API의 주소를 넣고, Callback URL에 “{REST API 주소}/naver/login”, “{REST API 주소}/naver/token”을 추가한다.

내 경우에는

  • 서비스 URL

“https://s80lt7nefi.execute-api.ap-northeast-2.amazonaws.com/api”

  • Callback URL

“https://s80lt7nefi.execute-api.ap-northeast-2.amazonaws.com/api/naver/login”

“https://s80lt7nefi.execute-api.ap-northeast-2.amazonaws.com/api/naver/token”

이다.


서버 코딩

아래 내용을 해당 파일에 그대로 코딩한다. /naver/login 경로의 location에 있는 callback을 통해 앱으로 redirect 해준다.

index.js
'use_strict';

const naver_auth = require('naver_auth');

exports.handler = async (event) => {
    switch (event.path) {
        case '/naver/login':
            if (event.httpMethod === 'GET') {
                const params = event.queryStringParameters;
                return {
                    statusCode: 307,
                    headers: {
                        Location: `callback://success?${new URLSearchParams(params)}`
                    },
                    body: JSON.stringify(params)
                };
            }
            break;
        
        case '/naver/token':
            if (event.httpMethod === 'GET') {
                const accessToken = event.queryStringParameters.accessToken;
                const result = await naver_auth.createFirebaseToken(accessToken);
                return {
                    statusCode: 200,
                    body: result
                };
            }
            break;
    }
};


네이버로부터 토큰을 발급받는 함수들을 만들어준다.

'use strict';

const admin = require('./firebase_admin.js');
const axios = require('axios');

const URL = 'https://openapi.naver.com/v1/nid/me';

async function requestMe(accessToken) {
    const result = await axios.get(URL, {
        method: 'GET',
        headers: {'Authorization': 'Bearer ' + accessToken}
    });
    return result.data;
}

async function updateOrCreateUser(userId, email, displayName, photoURL) {
    const updateParams = {
        provider: 'NAVER',
        displayName: displayName,
    };
    if (displayName) {
        updateParams['displayName'] = displayName;
    } else {
        updateParams['displayName'] = email;
    }
    if (photoURL) {
        updateParams['photoURL'] = photoURL;
    }
    try {
        return await admin.auth().updateUser(userId, updateParams);
    } catch (e) {
        if (e.code === 'auth/user-not-found') {
            updateParams['uid'] = userId;
            if (email) {
                updateParams['email'] = email;
            }
            return await admin.auth().createUser(updateParams);    
        }
        throw (e);
    }
}

async function createFirebaseToken(accessToken) {
    const me = await requestMe(accessToken);
    const body = me.response;
    const userId = `naver:${body.id}`;
    const userRecord = await updateOrCreateUser(userId, body.email, body.nickname, null);
    const updateParams = {
        uid: userRecord.id,
        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;
    }
    return await admin.auth().createCustomToken(userId, {provider: 'NAVER'});
}

module.exports={
    createFirebaseToken
};


앱 코딩

여기까지 서버 설정을 마무리하고 Flutter 앱으로 가보자. 먼저 필요한 dependency를 추가해준다. 버전은 최신 버전을 확인하여 넣어주자.

dependencies:
  firebase_core: ^1.0.2
  firebase_auth: ^1.0.1
  uuid: ^3.0.2
  flutter_web_auth: ^0.2.4
  http: ^0.13.1


android/app/src/main/AndroidManifest.xml로 가서 아래 코드를 추가한다. android:scheme의 callback은 서버에서 redirect에 사용하는 값으로 동일하게 해주면 된다.

<activity android:name="com.linusu.flutter_web_auth.CallbackActivity" >
    <intent-filter android:label="flutter_web_auth">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="callback" />
    </intent-filter>
</activity>


로그인 함수를 만든다. 로그인 클릭 시 아래 함수를 실행시키자. Client ID와 Client Secret 부분은 Naver Developers에서 본인 애플리케이션에 해당하는 값을 넣는다.

static const String BASE_URL = 'https://s80lt7nefi.execute-api.ap-northeast-2.amazonaws.com/api';

Future<UserCredential> loginWithNaver() async {
  final clientState = Uuid().v4();
  final authUri = Uri.https('nid.naver.com', '/oauth2.0/authorize', {
    'response_type': 'code',
    'client_id': {Client ID},
    'response_mode': 'form_post',
    'redirect_uri': '$BASE_URL/naver/login',
    'state': clientState,
  });
  final authResponse = await FlutterWebAuth.authenticate(
      url: authUri.toString(),
      callbackUrlScheme: "webauthcallback"
  );
  final code = Uri.parse(authResponse).queryParameters['code'];
  final tokenUri = Uri.https('nid.naver.com', '/oauth2.0/token', {
    'grant_type': 'authorization_code',
    'client_id': {Client ID},
    'client_secret': {Client Secret},
    'code': code,
    'state': clientState,
  });
  var tokenResult = await http.post(tokenUri);
  final accessToken = json.decode(tokenResult.body)['access_token'];
  final response = await http.get(
      Uri.parse('$BASE_URL/naver/token?accessToken=$accessToken')
  );
  return FirebaseAuth.instance.signInWithCustomToken(response.body);
}


로그인 후 UserCredential에서 원하는 데이터를 가져오면 된다. 아래는 이메일을 가져와서 보여주는 예시이다.

3이미 로그인이 되어 있어서 로그인 창은 뜨지 않음


길고 긴 로그인이 끝났다! 다른 서비스 로그인에도 그대로 적용할 수 있으니 쉽게 재사용 할 수 있을 것이다. 다음은 카카오 로그인을 해보도록 하겠다.


[Flutter] 네이버, 카카오 Social Login 구현 (3. 카카오 로그인 구현)