簡體   English   中英

從 javascript [spotify auth] 的彈出窗口中獲取訪問令牌 url

[英]getting access token url from popup in javascript [spotify auth]

我正在嘗試使用純 javascript 制作 Spotify 身份驗證流程,以便用戶可以登錄,然后我可以為他們的帳戶添加新的播放列表。 根據我閱讀的說明,我使用了一個身份驗證彈出窗口,一旦他們登錄,URL 中就會有訪問令牌。 我現在有一個彈出窗口,用戶可以使用它進行身份驗證,一旦他們這樣做,URL 中就會有訪問令牌。

我需要從彈出窗口中獲取 url 並將其保存為全局變量,但我無法弄清楚如何在 javascript 中執行此操作。

https://codepen.io/martin-barker/pen/YzPwXaz

我的代碼筆用let popup = window.open( ,我可以在我的彈出窗口中運行一個函數來檢測用戶何時成功通過身份驗證和 url 更改嗎?在這種情況下,我想保存 url 進行解析並關閉我的彈出窗口

我的javascript代碼如下:

async function spotifyAuth() {
let result = spotifyLogin()
}

//open popup
function spotifyLogin() {
console.log("inside spotifyLogin, opening popup")

let popup = window.open(`https://accounts.spotify.com/authorize?client_id=5a576333cfb1417fbffbfa3931b00478&response_type=token&redirect_uri=https://codepen.io/martin-barker/pen/YzPwXaz&show_dialog=true&scope=playlist-modify-public`, 'Login with Spotify', 'width=800,height=600')

}

//get url from popup and parse access token????
window.spotifyCallback = (payload) => {
console.log("inside window? ") //this line never appears in console
popup.close()
fetch('https://api.spotify.com/v1/me', {
headers: {
'Authorization': `Bearer ${payload}`
}
}).then(response => {
return response.json()
}).then(data => {
// do something with data
})
}

這是我在 JavaScript 中的做法。 像你提到的全局變量:

var access_token = null;

我的 url 看起來像這樣,例如: https://...home.jsp#access_token=BQAXe5JQOV_xZmAukmw6G430lreF......rQByzZMcOIF2q2aszujN0wzV7pIxA4viMbQD6s&token_type=Bearer&expires0&Yecod=Bearer&expires0&YeOdc

在 Spotify 將用戶重定向到您在儀表板上指定的 uri 后,我解析包含訪問令牌的哈希的 url,如下所示:

var hash = window.location.hash.substring(1);
var accessString = hash.indexOf("&");

/* 13 because that bypasses 'access_token' string */
access_token = hash.substring(13, accessString);
console.log("Access Token: " + access_token);

輸出是:

Access Token: BQAXe5JQOV_xZmAukmw6G430lreF...........rQByzZMcOIF2q2aszujN0wzV7pIxA4viMbQD6s

我將此訪問令牌保存在 sessionStorage 中,以防萬一用戶導航離開頁面並且 url 不包含 access_token。 我假設這是隱式授權流程,因為您想使用純 JavaScript。 只要確保在它們過期后每小時重新獲取一個訪問令牌。

附錄

我可以向您展示如何獲取令牌並在示例中使用它。

我在 .html 頁面上有一個按鈕,單擊該按鈕后會在名為

測試.js

function implicitGrantFlow() {

/* If access token has been assigned in the past and is not expired, no request required. */
if (sessionStorage.getItem("accessToken") !== null &&
    sessionStorage.getItem("tokenTimeStamp") !== null &&
    upTokenTime < tokenExpireSec) {
        var timeLeft = (tokenExpireSec - upTokenTime);
        console.log("Token still valid: " + Math.floor(timeLeft / 60) + " minutes left.");

        /* Navigate to the home page. */
        $(location).attr('href', "home.jsp");
} else {
    console.log("Token expired or never found, getting new token.");
    $.ajax({
        url: auth_url,
        type: 'GET',
        contentType: 'application/json',
        data: {
            client_id: client_id,
            redirect_uri: redirect_uri,
            scope: scopes,
            response_type: response_type_token,
            state: state
        }
    }).done(function callback(response) {
        /* Redirect user to home page */
        console.log("COULD THIS BE A SUCCESS?");
        $(location).attr('href', this.url);

    }).fail(function (error) {
        /* Since we cannot modify the server, we will always fail. */
        console.log("ERROR HAPPENED: " + error.status);
        console.log(this.url);
        $(location).attr('href', this.url);
    });
}

我正在做的是檢查我存儲在 sessionStorage 中的 access_token 信息是否為空。 我使用自 Epoch 以來的時間來生成令牌的創建時間以及理想情況下的到期時間。 如果滿足這些參數,則我不會再撥打電話。

否則,我會打電話獲取訪問令牌,成功后會將我重定向到我的 uri,正如我在之前的文章中提到的(你會看到我在 .fail 部分有重定向。這是由於我沒有有權在我的學校服務器上設置設置以繞過 CORS 相關問題,即使我創建的重定向 url 沒有問題,我的呼叫也無法成功。)。

然后當我的白名單 uri 被加載(重定向到我的主頁)時,我使用我的<body>標簽。

主頁.jsp

<body onload="getAccessToken()">

在我的標簽中,我讓它在頁面加載后調用此函數。 這將調用函數 getAccessTokens()。

/**
 * The bread and butter to calling the API. This function will be called once the
 * user is redirected to the home page on success and without rejecting the terms
 * we are demanding. Once through, this function parses the url for the access token
 * and then stores it to be used later or when navigating away from the home page.
 */
function getAccessToken() {

    access_token = sessionStorage.getItem("accessToken");

    if (access_token === null) {
        if (window.location.hash) {
            console.log('Getting Access Token');

            var hash = window.location.hash.substring(1);
            var accessString = hash.indexOf("&");

            /* 13 because that bypasses 'access_token' string */
            access_token = hash.substring(13, accessString);
            console.log("Access Token: " + access_token);

            /* If first visit or regaining token, store it in session. */    
            if (typeof(Storage) !== "undefined") {
                /* Store the access token */
                sessionStorage.setItem("accessToken", access_token); // store token.

                /* To see if we need a new token later. */
                sessionStorage.setItem("tokenTimeStamp", secondsSinceEpoch);

                /* Token expire time */
                sessionStorage.setItem("tokenExpireStamp", secondsSinceEpoch + 3600);
                console.log("Access Token Time Stamp: "
                + sessionStorage.getItem("tokenTimeStamp")
                + " seconds\nOR: " + dateNowMS + "\nToken expires at: "
                + sessionStorage.getItem("tokenExpireStamp"));
            } else {
                alert("Your browser does not support web storage...\nPlease try another browser.");
            }
        } else {
            console.log('URL has no hash; no access token');
        }
    } else if (upTokenTime >= tokenExpireSec) {
        console.log("Getting a new acess token...Redirecting");

        /* Remove session vars so we dont have to check in implicitGrantFlow */
        sessionStorage.clear();

        $(location).attr('href', 'index.html'); // Get another access token, redirect back.

    } else {
        var timeLeft = (tokenExpireSec - upTokenTime);
        console.log("Token still valid: " + Math.floor(timeLeft / 60) + " minutes left.");
    }

在這里,一旦我從 url 獲取訪問令牌,我就會將令牌存儲在會話存儲中。 我使用了我之前的帖子中提到的過程,但這里是完整的 JavaScript。 如果評論后仍然不清楚,請告訴我。

現在我們已經獲得並存儲了訪問令牌,我們現在可以進行 api 調用。 這是我的做法(並且一直在使用 qQuery,這是獲取用戶熱門曲目的示例)。

示例 api 調用

/**
 * Function will get the user's top tracks depending on the limit and offset
 * specified in addition to the time_range specified in JSON format.
 * @param time_range short/medium/long range the specifies how long ago.
 * @param offset Where the indexing of top tracks starts.
 * @param limit How many tracks at a time we can fetch (50 max.)
 */
function getUserTopTracks(time_range, offset, limit) {

$.get({
    url: 'https://api.spotify.com/v1/me/top/tracks',
    headers: {
        'Authorization': 'Bearer ' + access_token,
    },
    data: {
        limit: limit, // This is how many tracks to show (50 max @ a time).
        offset: offset, // 0 = top of list, increase to get more tracks.
        time_range: time_range // short/medium/long_term time ranges.
    },
    success: function (response) {

        /* Get the items from the response (The limit) tracks. */
        res = JSON.parse(JSON.stringify(response.items));

        /* Get all the track details in the json */
        for (i = 0; i < res.length; i++) {
            console.log("Track: " + res[i]);
        }
    },
    fail: function () {
        console.log("getUserTopTracks(): api call failed!");
    }
});

參數 time_range 被指定為“long_term”以獲取用戶從一開始的熱門曲目(在 Spotify 的文檔上閱讀更多信息以獲取更多信息),此外偏移量為 0 以從頭開始,限制等於 50,因為這是最大值每次調用獲取。

成功后,我有我的響應變量“response”,然后我希望解析的根從“items”部分開始,以使解析更容易(您不必這樣做,您可以簡單地使用 response.xxx.items。 xxx)。 然后我將響應打印到控制台。

這是您可以做的基本事情,您決定如何處理或存儲數據取決於您。 我不是專家,我上學期才開始學習網絡編程,我所做的很多實踐可能是錯誤的或不正確的。

你走在正確的軌道上。

彈出窗口會將您重定向到您在redirect_uri=...下添加的網站。 它將代碼和狀態查詢參數添加到該 url。

因此,在作為您的redirect_uri主機的網頁上,您可以解析完整的 URL。

不可能在單個頁面上完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM