前言
大家好,我是 Ryan,这篇文章是我参与 iThome 2022 铁人赛时与大家分享使用 Nuxt 3 串接 Google OAuth 登入的额外分享,因为在使用 Nuxt 3 串接 Google OAuth 其实等同于在 Vue 3 中做实现,所以独立了一篇 Vue 3 的範例来分享给大家。
为了让专案更乾净,本篇範例使用的是 Vue 3 + Vite 的模板,大家也可以参考下列指令做建立。
npm create vite@latest vue3-google-oauth-example -- --template vue
使用 OAuth 2.0 存取 Google API
首先,我们需要有一组 Google OAuth 使用的 Client ID,你可以到 Google Console 新增一个「OAuth 2.0 用户端 ID」,这里我就不再赘述网页应用程式用的申请过程。
这边提醒,在建立 OAuth Client ID 时,已授权的 JavaScript 来源,记得填写上您的正式环境或开发环境的 Domain,且建议使用 HTTPS。
完成后,记得保管好用户端密码,用户端 ID (Client ID) 是我们稍后会需要的,用户端编号格式大概如:
168152363730-b37gnijdpa2rdvvbq0qc29cjh4082t3b.apps.googleusercontent.com
接下来,安装 Vue 的 Google OAuth 插件,这边使用的是 vue3-google-login,也有不错的说明文件可以参考。
使用 NPM 安装 vue3-google-login。
npm install -D vue3-google-login
接着我们在元件中可以直接使用 <GoogleLogin>
元件,并添加一个 callback
属性。
<script setup>import { ref } from 'vue'const data = ref()const callback = (response) => { data.value = response}</script><template> <div> <GoogleLogin :callback="callback" /> <p> {{ data }} </p> </div></template><style scoped>p { margin-top: 12px; word-break: break-all;}</style>
接着我们使用 npm run dev
来启动开发伺服器,就能发现使用 Google 帐号登入成功后,所返回的 Credential。
One Tap prompt
你可以在 <GoogleLogin>
元件添加 prompt
属性并设为 true
,这样就能同时启用 Google 一键登入 (One Tap prompt) 的功能啰!
<GoogleLogin :callback="callback" prompt/>
或者也可以在 onMounted
中呼叫 vue3-google-login 的 googleOneTap()
方法,来单独使用 One Tap prompt。
<script setup>import { onMounted } from 'vue'import { googleOneTap } from 'vue3-google-login'onMounted(() => { googleOneTap() .then((response) => { console.log(response) }) .catch((error) => { console.error(error) })})</script>
自订按钮
如果你想自订登入按钮的样式,可以在 <GoogleLogin>
的预设插槽 (Slot) 做建立。
<template> <GoogleLogin :callback="callback"> <button>使用 Google 进行登入</button> </GoogleLogin></template>
使用自订按钮会让 OAuth 流程稍微有点不一样,当你登入成功后预设会回传 Auth Code。
如果设定属性 popup-type="TOKEN"
,则回传 Access Token。
<template> <GoogleLogin :callback="callback" popup-type="TOKEN"> <button>使用 Google 进行登入</button> </GoogleLogin></template>
使用 googleTokenLogin()
在元件中我们也可以自己建立 handleGoogleAccessTokenLogin
点击事件,呼叫 googleTokenLogin()
方法并传入设定在 Runtime Config 中的 Google Client ID,这样点击登入按钮就能处理 Google 登入取得 Access Token。
<script setup>import { ref } from 'vue'import { googleTokenLogin } from 'vue3-google-login'const GOOGLE_CLIENT_ID = '这边放上你的 Google Client ID'const data = ref()const handleGoogleAccessTokenLogin = () => { googleTokenLogin({ clientId: GOOGLE_CLIENT_ID }).then((response) => { data.value = response })}</script>
建立一个登入按钮来呼叫 handleGoogleAccessTokenLogin
点击事件。
<template> <div> <button type="button" @click="handleGoogleAccessTokenLogin" > 使用 Google 进行登入 </button></template>
使用 vue3-google-login 提供的 googleTokenLogin()
方法,我们就能取得 Google 使用者的 Access Token 啰!
使用 googleAuthCodeLogin()
我们也可以使用 googleAuthCodeLogin()
来取得 Auth Code。
<script setup>import { ref } from 'vue'import { googleAuthCodeLogin } from 'vue3-google-login'const GOOGLE_CLIENT_ID = '这边放上你的 Google Client ID'const data = ref()const handleGoogleAuthCodeLogin = () => { googleAuthCodeLogin({ clientId: GOOGLE_CLIENT_ID }).then((response) => { data.value = response })}</script>
建立一个登入按钮来呼叫 handleGoogleAuthCodeLogin
点击事件。
<template> <div> <button type="button" @click="handleGoogleAuthCodeLogin" > 使用 Google 进行登入 </button></template>
取得的就会是 Auth Code。
伺服器端验证
当使用者于前端成功登入后,通常会传至后端进行登入或记录使用者,再产生使用于网站的 Token、Cookie 或 Session 等,以供后续的网站验证做使用。
我们可使用 google-auth-library 于后端进行一系列的验证或取得使用者资讯。
使用 NPM 安装 google-auth-library。
npm install -D google-auth-library
接下来,我们就能依照不同的登入方式取得的 Credential
、Access Token
或 Auth Code
送至后端做验证。
验证 Access Token
import { OAuth2Client } from 'google-auth-library'export default (async (accessToken) => { const oauth2Client = new OAuth2Client() oauth2Client.setCredentials({ access_token: accessToken }) const userInfo = await oauth2Client .request({ url: 'https://www.googleapis.com/oauth2/v3/userinfo' }) .then((response) => response.data) .catch(() => null) oauth2Client.revokeCredentials() return { id: userInfo.sub, name: userInfo.name, avatar: userInfo.picture, email: userInfo.email, emailVerified: userInfo.email_verified, }})
验证 Credential
在元件中,我们使用的登入方式如果是Google 预设渲染的按钮或 One Tap prompt,回传值就会包含 Credential
,我们将就可使用下面修改后的 Server API 进行验证。
import { OAuth2Client } from 'google-auth-library'export default (async (credential) => { const oauth2Client = new OAuth2Client() const ticket = await oauth2Client.verifyIdToken({ idToken: credential, }) const payload = ticket.getPayload() return { id: payload.sub, name: payload.name, avatar: payload.picture, email: payload.email, emailVerified: payload.email_verified }})
验证 Auth Code
import { OAuth2Client } from 'google-auth-library'export default (async (authCode) => { const oauth2Client = new OAuth2Client({ clientId: '你的 Google Client ID', clientSecret: '你的 Google Client Secret', redirectUri: '你的 Google Redirect Uri' }) let { tokens } = await oauth2Client.getToken(authCode) client.setCredentials({ access_token: tokens.access_token }) const userInfo = await oauth2Client .request({ url: 'https://www.googleapis.com/oauth2/v3/userinfo' }) .then((response) => response.data) .catch(() => null) oauth2Client.revokeCredentials() return { id: userInfo.sub, name: userInfo.name, avatar: userInfo.picture, email: userInfo.email, emailVerified: userInfo.email_verified, }})
小结
这篇文章记录了实现了串接 Google OAuth 登入,大家可以在依照使用情境自己挑选登入方式并将 Access Token
等其他资讯发送至后端进行验证,后续也能将使用者资讯储存到资料库中,有了资料库我们就能依照使用者资讯,来比对资料库进行注册、验证登入及产生后续的 Session 或 Cookie 等。
感谢大家的阅读,欢迎大家给予建议 :)
此外我正在参与 iThome 铁人赛,主题是 Nuxt 3 学习笔记,
如果对 Nuxt 3 系列感兴趣,可以订阅接收通知,也欢迎分享给喜欢或正在学习 Nuxt 3 的伙伴。