请求帮助:为Spotify艺人信息查询代码添加自动刷新Token功能
Got it, let's tackle this Spotify token auto-refresh issue in your ASP.NET Web Forms project. The key here is leveraging Spotify's refresh token, which lets you get a new access token without requiring the user to re-authenticate every hour. Here's a step-by-step implementation tailored to your aspx/aspx.cs setup:
1. Make Sure You Request the offline_access Scope First
This is non-negotiable—Spotify only issues a refresh token if your initial authorization request includes the offline_access scope. Update your authorization redirect URL to include it:
// In your authorization page's code-behind (e.g., AuthorizeSpotify.aspx.cs) protected void Page_Load(object sender, EventArgs e) { string clientId = ConfigurationManager.AppSettings["SpotifyClientId"]; string redirectUri = ConfigurationManager.AppSettings["SpotifyRedirectUri"]; // Include offline_access in the scope list string scope = "user-read-private user-read-email offline_access"; // Add any other scopes you need string authUrl = $"https://accounts.spotify.com/authorize?client_id={clientId}&response_type=code&redirect_uri={Uri.EscapeDataString(redirectUri)}&scope={Uri.EscapeDataString(scope)}"; Response.Redirect(authUrl); }
2. Store the Refresh Token and Token Expiry Date
When you first exchange the authorization code for an access token, Spotify will return a refresh token. Store this securely (along with the access token and its expiry time) — you can use Session for single-user scenarios, or a database for multi-user apps.
First, define a model to parse the token response:
// Add this class to your project (e.g., in a Models folder) public class SpotifyTokenResponse { [JsonPropertyName("access_token")] public string AccessToken { get; set; } [JsonPropertyName("token_type")] public string TokenType { get; set; } [JsonPropertyName("expires_in")] public int ExpiresIn { get; set; } [JsonPropertyName("refresh_token")] public string RefreshToken { get; set; } [JsonPropertyName("scope")] public string Scope { get; set; } }
Then, in your redirect callback page (where you exchange the code for tokens):
// In your callback page's code-behind (e.g., SpotifyCallback.aspx.cs) protected async void Page_Load(object sender, EventArgs e) { string code = Request.QueryString["code"]; if (string.IsNullOrEmpty(code)) return; string clientId = ConfigurationManager.AppSettings["SpotifyClientId"]; string clientSecret = ConfigurationManager.AppSettings["SpotifyClientSecret"]; string redirectUri = ConfigurationManager.AppSettings["SpotifyRedirectUri"]; using (var client = new HttpClient()) { var formData = new Dictionary<string, string> { ["grant_type"] = "authorization_code", ["code"] = code, ["redirect_uri"] = redirectUri, ["client_id"] = clientId, ["client_secret"] = clientSecret }; var response = await client.PostAsync("https://accounts.spotify.com/api/token", new FormUrlEncodedContent(formData)); response.EnsureSuccessStatusCode(); var tokenData = await response.Content.ReadFromJsonAsync<SpotifyTokenResponse>(); // Store tokens in Session (adjust for database if needed) Session["SpotifyAccessToken"] = tokenData.AccessToken; Session["SpotifyRefreshToken"] = tokenData.RefreshToken; // Calculate expiry time (add expires_in seconds to current time) Session["SpotifyTokenExpiresAt"] = DateTime.Now.AddSeconds(tokenData.ExpiresIn); // Redirect back to your search page Response.Redirect("~/SpotifySearch.aspx"); } }
3. Add a Method to Refresh the Access Token
Create a reusable method that uses the stored refresh token to get a new access token. This will run automatically when the current token is about to expire.
// In your search page's code-behind (e.g., SpotifySearch.aspx.cs) private async Task RefreshAccessToken() { string refreshToken = Session["SpotifyRefreshToken"] as string; if (string.IsNullOrEmpty(refreshToken)) { // No refresh token available—redirect to re-authorize Response.Redirect("~/AuthorizeSpotify.aspx"); return; } string clientId = ConfigurationManager.AppSettings["SpotifyClientId"]; string clientSecret = ConfigurationManager.AppSettings["SpotifyClientSecret"]; using (var client = new HttpClient()) { var formData = new Dictionary<string, string> { ["grant_type"] = "refresh_token", ["refresh_token"] = refreshToken, ["client_id"] = clientId, ["client_secret"] = clientSecret }; var response = await client.PostAsync("https://accounts.spotify.com/api/token", new FormUrlEncodedContent(formData)); if (!response.IsSuccessStatusCode) { // Refresh failed (e.g., token revoked)—redirect to re-authorize Response.Redirect("~/AuthorizeSpotify.aspx"); return; } var tokenData = await response.Content.ReadFromJsonAsync<SpotifyTokenResponse>(); // Update stored tokens Session["SpotifyAccessToken"] = tokenData.AccessToken; // Spotify may return a new refresh token—update it if provided if (!string.IsNullOrEmpty(tokenData.RefreshToken)) { Session["SpotifyRefreshToken"] = tokenData.RefreshToken; } Session["SpotifyTokenExpiresAt"] = DateTime.Now.AddSeconds(tokenData.ExpiresIn); } }
4. Check Token Validity Before Calling Spotify API
Add a helper method to check if the current token is still valid (or about to expire) and refresh it if needed. Call this method before any Spotify API request.
// In SpotifySearch.aspx.cs private async Task EnsureValidToken() { DateTime? expiresAt = Session["SpotifyTokenExpiresAt"] as DateTime?; // Refresh token 5 minutes before it expires to avoid race conditions if (!expiresAt.HasValue || DateTime.Now >= expiresAt.Value.AddMinutes(-5)) { await RefreshAccessToken(); } } // Example method to fetch artist info (your existing search functionality) public async Task<string> GetArtistInfo(string artistName) { await EnsureValidToken(); string accessToken = Session["SpotifyAccessToken"] as string; using (var client = new HttpClient()) { client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); var response = await client.GetAsync($"https://api.spotify.com/v1/search?q={Uri.EscapeDataString(artistName)}&type=artist"); response.EnsureSuccessStatusCode(); return await response.Content.ReadAsStringAsync(); } }
Key Notes for Production
- Secure Storage: Never hardcode your
client_idorclient_secret—store them inWeb.configunder<appSettings>or use environment variables. - Multi-User Apps: If your app has multiple users, replace
Sessionwith a database table that links refresh tokens to user accounts. - Error Handling: Add more robust error handling for network failures or token revocation scenarios.
- Background Refresh: If you need to refresh tokens even when the user isn't active, consider using a background service (like Hangfire) instead of checking on each request.
内容的提问来源于stack exchange,提问作者James

