Google 的第三方登入 (web 前端實作)

  1. Google 的第三方登入 (web 前端實作)
    1. 概念介紹
      1. 前端的第三方登入
    2. 設定
    3. 實作
      1. Google initial
      2. 繪製 Button
      3. 登出

Google 的第三方登入 (web 前端實作)

概念介紹

要實現第三方登入,有兩種方式

  1. 做在前端 ← 這一篇要講的是這個
  2. 做在後端

前端的第三方登入

兩者之間的差別在於,前端實作,不需要 redirect url 後端實作的話,需要。(慎選套件)
這一篇,介紹的是做在前端。

這次是要介紹如何妥善安排程式碼在 Vue 裡面。

設定

先到 Google 設定第三方登入的憑證

這個頁面

  1. 如果畫面和我不一樣的話,請先開一個專案
  2. 我們要的功能在「憑證」裡面
  3. 在憑證裡面,建立一個「OAuth 用戶端 ID」允許第三方登入

點擊 OAuth 用戶端 ID 之後

  1. 因為要要做的是 web 所以選「網頁應用程式」
  2. 設定 URI 可以用 ngrok 先用一個臨時的來測試。(在此就用 http://127.0.0.1:8080 做代表)
  3. 好了就按下「建立」

  1. 成功的時候,Google 就會提供用戶端 ID (clientId) 和用戶端密碼,我們只要 clientId
  2. 按下確定,就可以來實作程式囉

實作

官方網站

public/index.html

需要載入 Google 的 SDK[1]

<script src="https://apis.google.com/js/platform.js" async defer></script>

Google initial

在頁面初始的過程,需要在 gapi.load 時初始化或自動登入[2]

example code

var startApp = function() {
gapi.load('auth2', function(){
// Retrieve the singleton for the GoogleAuth library and set up the client.
auth2 = gapi.auth2.init({
client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
cookiepolicy: 'single_host_origin',
// Request scopes in addition to 'profile' and 'email'
//scope: 'additional_scope'
});
attachSignin(document.getElementById('customBtn'));
});
};

在 vue 上實作,必須將這一段放在 main.js 確保不管已登入,還是未登入,在每一次開啟頁面,都會正確初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import Vue from 'vue';
import App from './App';
import router from './router';

Vue.config.productionTip = false;

new Vue({
created() {
// Google Sign-in initial
window.gapi.load('auth2', () => {
window.gapi.auth2.init({
client_id: 'YOUR_CLIENT_ID.apps.googleusercontent.com',
});
});
},
router,
render: h => h(App)
}).$mount('#app');

繪製 Button

可以使用 gapi.signin2.render 自訂義繪製時機點

example code

gapi.signin2.render('my-signin2', {
'scope': 'profile email',
'width': 240,
'height': 50,
'longtitle': true,
'theme': 'dark',
'onsuccess': onSuccess,
'onfailure': onFailure
});

src/components/googleSigninButton.vue

直接將 google sign-in button 做成一個按鈕。
並且在 mounted 時繪制

Note
<div class="g-signin2" data-onsuccess="onSignIn"></div>
這種內建的方式繪製,它只會在網頁初始時繪製按鈕。

但是登出時會出問題:
按下登出後,會跳轉到登入頁,照理需要繪製登入按鈕
因為這並不是在初始過程,所以不會繪製。

登入 method 的綁定方式,要配合 Google API 的做法
在此,目的是為了傳給後端 id_token 所以輸出只 emit 出 id_token 而已。
這部份可以依需求修改。

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
36
37
38
<template>
<div>
<div id="google-sign-in-button"></div>
</div>
</template>

<script>
export default {
name: 'GoogleSignInButton',
props: {
width: {
type: String,
default: null
},
height: {
type: String,
default: null
}
},
mounted() {
window.gapi.signin2.render('google-sign-in-button', {
scope: 'profile email',
width: this.width,
height: this.height,
longtitle: true,
theme: 'light',
onsuccess: this.signIn,
onfailure: () => {}
});
},
methods: {
signIn(googleUser) {
const id_token = googleUser.getAuthResponse().id_token;
this.$emit('sign-in', id_token);
}
}
};
</script>

使用 GoogleSignInButton component

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
<template>
<div>
<GoogleSignInButton @sign-in="oAuthSignIn('google', $event)"></GoogleSignInButton>
</div>
</template>

<script>
import GoogleSignInButton from '@/components/GoogleSignInButton';

export default {
name: 'AuthSignin',
components: {
GoogleSignInButton
},
methods: {
async oAuthSignIn(provider, id_token) {
try {
await this.$store.dispatch('oAuthLogin', {
provider,
id_token
});
this.$emit('submit');
} catch (error) {
console.error(error);
}
}
}
};
</script>

登出

若你想要在登出時,同時斷開使用者給予的授權,就可以增加這一段。[3]

example code

<a href="#" onclick="signOut();">Sign out</a>
<script>
function signOut() {
var auth2 = gapi.auth2.getAuthInstance();
auth2.signOut().then(function () {
console.log('User signed out.');
});
}
</script>

src/views/navigation.vue

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
36
<template>
<div class="shadow">
<botton @click="Logout">登出</botton>
</div>
</template>

<script>
export default {
name: 'Navigation',
methods: {
async Logout() {
try {
const isLogout = window.confirm('確定要登出');
if (isLogout) {
const auth2 = window.gapi.auth2.getAuthInstance();
auth2.signOut().then(() => {
console.log('Google User signed out.');
});
// 可以在這個時候移除 cookie
window.alert('已登出');
this.$router.push({ name: 'Signin' }); // 回到登入頁
}
} catch (error) {
if (error instanceof Error) {
window.alert(error.messages);
} else {
window.alert(error.detail);
}
}
}
}
};
</script>

<style lang="scss" scoped>
</style>

  1. 加載 Google 平台庫 - 將 Google Sign-In 集成到您的網絡應用程序中) ↩︎

  2. 使用自定義圖形構建按鈕 - 構建自定義 Google 登錄按鈕 | 網站的 Google 登錄 ↩︎

  3. 註銷用戶 - 將 Google Sign-In 集成到您的網絡應用程序中 ↩︎