Looker 採用 OAuth,讓 OAuth 用戶端應用程式向 Looker API 驗證,而不向執行 OAuth 用戶端應用程式的瀏覽器,公開用戶端 ID 和用戶端密鑰。
使用 OAuth 的網頁應用程式必須符合下列規定:
- 使用 OAuth 驗證僅適用於 Looker API 4.0。
- OAuth 用戶端應用程式必須先透過 API 向 Looker 註冊,應用程式使用者才能驗證 Looker。
- 用戶端應用程式必須使用 HTTPS,向 Looker API 傳送所有要求。用戶端應用程式如要使用瀏覽器提供的
SubtleCryptoAPI,必須由 HTTPS 代管。
Looker API CORS 支援
Looker API 支援使用跨源資源共享 (CORS) 通訊協定,在瀏覽器和跨來源呼叫。Looker CORS 支援功能有下列需求條件:
只有嵌入網域許可清單中的來源,才能使用 CORS 呼叫 API。
只有透過 OAuth 或呼叫
/loginAPI 端點取得的存取權杖,才能使用 CORS 呼叫 Looker API。
OAuth 驗證總覽
OAuth 驗證程序大致如下:
- 在 Looker 執行個體註冊 OAuth 用戶端應用程式。
將 OAuth 用戶端應用程式的來源新增至嵌入網域許可清單,以便進行程式碼交換 API 呼叫和任何後續的 CORS API 呼叫。
當 OAuth 用戶端應用程式嘗試驗證使用者時,請將瀏覽器網址重新導向至 Looker UI 主機名稱 (而非 Looker API 主機名稱) 上的
/auth端點。例如:https://instance_name.looker.com。如果使用者成功通過驗證並登入 Looker,Looker 會立即將 OAuth 重新導向傳回 OAuth 用戶端應用程式。如果使用者尚未在裝置和瀏覽器上登入 Looker,系統會顯示 Looker 登入畫面,並提示使用者使用一般驗證通訊協定登入 Looker 使用者帳戶。
使用 OAuth 重新導向傳回的授權碼,OAuth 用戶端應用程式接下來應呼叫 Looker API 主機名稱上的
/token端點,例如https://instance_name.looker.com:19999。API 主機名稱可能與 Looker UI 主機名稱相同,也可能不同。/token端點僅存在於 Looker API 主機上,/auth端點僅存在於 Looker UI 主機上。如果傳遞至
/token端點的授權碼有效,Looker 會傳回 APIaccess_token,為來自 OAuth 用戶端應用程式網域的 CORS API 要求啟用。
註冊 OAuth 用戶端應用程式
每個 OAuth 用戶端應用程式嘗試使用 OAuth 向 Looker API 驗證身分時,都必須先向 Looker 執行個體註冊,Looker 才會授權存取。
Looker 管理員可以直接在 Looker「管理」面板的「管理 OAuth 用戶端」頁面 (依序點選「管理」>「驗證」>「管理 OAuth 用戶端」),註冊及管理自訂 OAuth 用戶端應用程式。管理員可以透過這個介面執行下列工作:
- 為應用程式設定一或多個授權的重新導向 URI,以支援多個環境和通訊埠。
- 限制只有特定 Looker 使用者群組的成員才能取得授權 (Restrict to Group ID)。
- 查看、編輯、啟用、停用或刪除已註冊的自訂應用程式。
如需在管理面板中註冊自訂用戶端的逐步說明,請參閱「管理員設定 - 管理 OAuth 用戶端」說明文件頁面。
使用 API 透過程式輔助方式註冊
或者,管理員可以透過程式輔助方式註冊 OAuth 用戶端應用程式,方法是直接呼叫註冊 OAuth 應用程式端點,或在 Looker API Explorer 中執行。參數包括:
client_guid:應用程式的專屬字串 ID (開頭不得為com.looker.)。redirect_uris:一組已授權的回呼 URI,應用程式會在這些 URI 接收 OAuth 重新導向和授權碼。display_name:向使用者顯示的應用程式名稱。description:OAuth 用戶端應用程式的說明。group_id(選用):Looker 群組的數字 ID,用於限制存取權。
使用 OAuth 執行使用者登入
將使用者導向 UI 主機上的
/auth端點。例如:async function oauth_login() { const code_verifier = secure_random(32) const code_challenge = await sha256_hash(code_verifier) const params = { response_type: 'code', client_id: '123456', redirect_uri: 'https://mywebapp.com:3000/authenticated', scope: 'cors_api', state: '1235813', code_challenge_method: 'S256', code_challenge: code_challenge, } const url = `${base_url}?${new URLSearchParams(params).toString()}` // Replace base_url with your full Looker instance's UI host URL, plus the `/auth` endpoint. log(url) // Stash the code verifier we created in sessionStorage, which // will survive page loads caused by login redirects // The code verifier value is needed after the login redirect // to redeem the auth_code received for an access_token // sessionStorage.setItem('code_verifier', code_verifier) document.location = url } function array_to_hex(array) { return Array.from(array).map(b => b.toString(16).padStart(2,'0')).join('') } function secure_random(byte_count) { const array = new Uint8Array(byte_count); crypto.getRandomValues(array); return array_to_hex(array) } async function sha256_hash(message) { const msgUint8 = new TextEncoder().encode(message) const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8) return base64.urlEncode(hashBuffer)) // Refers to the implementation of base64.encode stored at https://gist.github.com/jhurliman/1250118 }Looker 會嘗試使用 Looker 執行個體設定的驗證系統驗證使用者。
- 如果使用者已在目前瀏覽器登入 Looker (即登入 Cookie 狀態為有效),系統就不會提示使用者輸入登入憑證。
- 如果使用者是首次透過這個 OAuth 用戶端應用程式登入,Looker 會顯示揭露和確認頁面,供使用者確認及接受。系統會顯示註冊應用程式時使用的
description參數文字。說明應指出應用程式打算如何使用使用者的 Looker 帳戶。使用者點選「接受」後,系統會將網頁重新導向至應用程式redirect_uri。 - 如果使用者已在目前的瀏覽器中登入 Looker,且已確認揭露頁面,OAuth 登入程序會立即完成,不會中斷畫面。
Looker API 會將 OAuth 重新導向傳回 OAuth 用戶端應用程式。儲存 URI 參數中列出的授權碼。以下是 OAuth 重新導向 URI 範例:
https://mywebapp.com:3000/authenticated?&code=asdfasdfassdf&state=...授權碼會顯示在 URI 的
&code=後方。在這個範例中,授權碼為asdfasdfassdf。向 Looker API 中的
/token端點發出網頁要求,並傳遞授權碼和應用程式資訊。例如:async function redeem_auth_code(response_str) { const params = new URLSearchParams(response_str) const auth_code = params.get('code') if (!auth_code) { log('ERROR: No authorization code in response') return } log(`auth code received: ${auth_code}`) log(`state: ${params.get('state')}`) const code_verifier = sessionStorage.getItem('code_verifier') if (!code_verifier) { log('ERROR: Missing code_verifier in session storage') return } sessionStorage.removeItem('code_verifier') const response = await fetch('https://mycompany.looker.com:19999/api/token', { // This is the URL of your Looker instance's API web service method: 'POST', mode: 'cors', // This line is required so that the browser will attempt a CORS request. body: stringify({ grant_type: 'authorization_code', client_id: '123456', redirect_uri: 'https://mywebapp.com:3000/authenticated', code: auth_code, code_verifier: code_verifier, }), headers: { 'x-looker-appid': 'Web App Auth & CORS API Demo', // This header is optional. 'Content-Type': 'application/json;charset=UTF-8' // This header is required. }, }).catch((error) => { log(`Error: ${error.message}`) }) const info = await response.json() log(`/api/token response: ${stringify(info)}`) // Store the access_token and other info, // which in this example is done in sessionStorage const expires_at = new Date(Date.now() + (info.expires_in * 1000)) info.expires_at = expires_at log(`Access token expires at ${expires_at.toLocaleTimeString()} local time.`) sessionStorage.setItem('access_info', stringify(info)) access_info = info }如果回應成功,OAuth 用戶端應用程式會收到 API
access_token。回應也會包含refresh_token,您之後可以使用這個值取得新的access_token,不需使用者互動。refresh_token的生命週期為一個月。妥善保存refresh_token。Looker 管理員隨時可以撤銷這個系統中的所有權杖。