אימות Looker API באמצעות OAuth

‫Looker משתמש ב-OAuth כדי לאפשר לאפליקציות לקוח OAuth לבצע אימות ב-Looker API בלי לחשוף את מזהי הלקוחות ואת סודות הלקוחות לדפדפן שבו פועלת אפליקציית הלקוח OAuth.

אפליקציות אינטרנט שמשתמשות ב-OAuth צריכות לעמוד בדרישות הבאות:

  • אימות באמצעות OAuth זמין רק ב-Looker API 4.0.
  • כדי שמשתמשי האפליקציה יוכלו לבצע אימות ב-Looker, קודם צריך לרשום את לקוחות OAuth ב-Looker באמצעות ה-API.
  • אפליקציות לקוח חייבות להשתמש ב-HTTPS לכל הבקשות ל-Looker API. אפליקציות לקוח שרוצות להשתמש בממשקי ה-API של SubtleCrypto שמסופקים על ידי הדפדפן חייבות להיות מאוחסנות ב-HTTPS.

תמיכה ב-CORS ב-Looker API

אפשר להפעיל את Looker API בדפדפן וממקורות שונים באמצעות פרוטוקול שיתוף משאבים בין מקורות (CORS). הדרישות לתמיכה ב-CORS ב-Looker הן:

  • רק מקורות שמופיעים ברשימת ההיתרים של הדומיינים המוטמעים יכולים לקרוא ל-API באמצעות CORS.

  • אפשר להשתמש ב-CORS כדי לבצע קריאות ל-Looker API רק באמצעות אסימוני גישה שהתקבלו מ-OAuth או מקריאה לנקודת קצה ל-API של /login.

    אי אפשר לבצע קריאה לנקודת קצה ל-API‏ /login באמצעות בקשות CORS. אפליקציות לקוח שרוצות לבצע קריאות ל-Looker API באמצעות בקשות CORS צריכות להשתמש בתהליך הכניסה באמצעות OAuth שמתואר במאמר ביצוע כניסת משתמש באמצעות OAuth, או לאחזר אסימון משרת האפליקציות או מקריאות API שאינן CORS.

סקירה כללית על אימות OAuth

סקירה כללית של תהליך האימות באמצעות OAuth:

  1. רושמים את לקוח OAuth ב-Looker API.
  2. מוסיפים את המקור של אפליקציית לקוח ה-OAuth לרשימת ההיתרים של הדומיין המוטמע עבור הקריאה ל-API של החלפת הקוד וכל קריאה ל-API של CORS שמתבצעת לאחר מכן.

  3. הפניה אוטומטית של כתובת ה-URL בדפדפן לנקודת הקצה /auth בשם המארח של ממשק המשתמש של Looker (לא בשם המארח של Looker API) כשיישום לקוח OAuth מנסה לאמת משתמש. לדוגמה, https://instance_name.looker.com.

  4. אם המשתמש מאומת בהצלחה ומתחבר ל-Looker, ‏ Looker מחזיר הפניה אוטומטית של OAuth לאפליקציית לקוח OAuth באופן מיידי. אם המשתמש לא מחובר כבר ל-Looker במכשיר ובדפדפן, יוצג מסך הכניסה ל-Looker והמשתמש יתבקש להתחבר לחשבון המשתמש שלו ב-Looker באמצעות פרוטוקול האימות הרגיל.

  5. באמצעות קוד ההרשאה שמוחזר בהפניה האוטומטית של OAuth, אפליקציית לקוח OAuth צריכה לבצע קריאה לנקודת הקצה /token בשם המארח של Looker API, לדוגמה, https://instance_name.looker.com:19999. יכול להיות ששם המארח של ה-API יהיה זהה לשם המארח של ממשק המשתמש של Looker, או שונה ממנו. נקודת הקצה /token קיימת רק במארח Looker API, ונקודת הקצה /auth קיימת רק במארח ממשק המשתמש של Looker.

  6. אם קוד ההרשאה שמועבר לנקודת הקצה /token תקף, Looker מחזיר API access_token שמופעל לבקשות API של CORS מהדומיין של אפליקציית לקוח OAuth.

רישום אפליקציית לקוח OAuth

כל אפליקציית לקוח OAuth שמנסה לבצע אימות ל-Looker API באמצעות OAuth צריכה להירשם קודם במופע Looker, לפני ש-Looker יאשר את הגישה. כדי לרשום אפליקציית לקוח OAuth:

  1. פותחים את API Explorer במופע Looker.
  2. בתפריט הנפתח של הגרסה, בוחרים בגרסה 4.0 – יציבה של ה-API.
  3. בשיטה Auth, מחפשים את נקודת הקצה ל-API ‏register_oauth_client_app(). אפשר גם לחפש 'אפליקציית OAuth' בשדה חיפוש. אתם יכולים להשתמש ב-register_oauth_client_app() כדי לרשום את אפליקציית לקוח OAuth שלכם ב-Looker. לוחצים על הלחצן Run It, מזינים את הפרמטרים ב-API Explorer ולוחצים שוב על Run It כדי לרשום את אפליקציית לקוח OAuth, או משתמשים בנקודת קצה ל-API של register_oauth_client_app() באופן פרוגרמטי. הפרמטרים הנדרשים register_oauth_client_app() הם:

    • client_guid: מזהה ייחודי גלובלי של האפליקציה
    • redirect_uri: ה-URI שבו האפליקציה תקבל הפניה אוטומטית של OAuth שכוללת קוד הרשאה
    • display_name: השם של האפליקציה שמוצג למשתמשים באפליקציה
    • description: תיאור של האפליקציה שמוצג למשתמשים בדף גילוי נאות ואישור, כשהמשתמש מתחבר בפעם הראשונה מהאפליקציה

    הערכים בפרמטרים client_guid ו-redirect_uri חייבים להיות בדיוק כמו הערכים שאפליקציית לקוח OAuth תספק, אחרת האימות יידחה.

ביצוע כניסה של משתמש באמצעות OAuth

  1. מפנים את המשתמש לנקודת הקצה /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 מתבצעת באופן מיידי ללא הפרעה ויזואלית.
  2. ממשק Looker API יחזיר הפניה אוטומטית של OAuth לאפליקציית לקוח OAuth. שומרים את קוד ההרשאה שמופיע בפרמטר URI. הדוגמה הבאה היא של URI להפניה אוטומטית של OAuth:

    https://mywebapp.com:3000/authenticated?&code=asdfasdfassdf&state=...
    

    קוד ההרשאה מוצג אחרי &code= ב-URI. בדוגמה הזו, קוד ההרשאה הוא asdfasdfassdf.

  3. שולחים בקשה לאחזור מהרשת לנקודת הקצה /token ב-Looker API, ומעבירים את קוד ההרשאה ואת פרטי האפליקציה. לדוגמה:

    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 יכול לבטל את כל האסימונים במערכת הזו בכל שלב.