169 lines
3.8 KiB
Markdown
169 lines
3.8 KiB
Markdown
# ✅ Hash 模式下的 Spotify OAuth 完美解决方案
|
||
|
||
## 🎯 最终方案
|
||
|
||
### 1. Spotify Dashboard 配置
|
||
|
||
**Redirect URIs:**
|
||
```
|
||
https://sports.rucky.cn/ (生产环境)
|
||
http://localhost:5173/ (开发环境)
|
||
```
|
||
|
||
⚠️ **重要:不要使用 hash 格式!**
|
||
- ❌ `https://sports.rucky.cn/#/callback`
|
||
- ✅ `https://sports.rucky.cn/`
|
||
|
||
### 2. 工作流程
|
||
|
||
```
|
||
用户点击"连接 Spotify 账号"
|
||
↓
|
||
跳转到 Spotify (redirect_uri=https://sports.rucky.cn/)
|
||
↓
|
||
用户授权
|
||
↓
|
||
Spotify 返回: https://sports.rucky.cn/?code=xxx&state=xxx
|
||
↓
|
||
Home.vue 检测到 code 参数
|
||
↓
|
||
保存参数到 sessionStorage
|
||
↓
|
||
跳转到 #/callback 路由
|
||
↓
|
||
SpotifyCallback.vue 处理授权
|
||
↓
|
||
授权成功,跳转到音乐律动页面
|
||
```
|
||
|
||
### 3. 关键代码
|
||
|
||
**MusicRhythm.vue:**
|
||
```typescript
|
||
// 使用根路径作为 redirect_uri
|
||
const REDIRECT_URI = window.location.origin + '/'
|
||
```
|
||
|
||
**Home.vue:**
|
||
```typescript
|
||
onMounted(() => {
|
||
// 检测 Spotify 回调
|
||
const urlParams = new URLSearchParams(window.location.search)
|
||
|
||
if (urlParams.has('code') && urlParams.has('state')) {
|
||
// 保存参数并跳转到 callback 路由
|
||
sessionStorage.setItem('spotify_callback_params', window.location.search)
|
||
router.replace('/callback')
|
||
}
|
||
})
|
||
```
|
||
|
||
**SpotifyCallback.vue:**
|
||
```typescript
|
||
onMounted(async () => {
|
||
// 从 sessionStorage 恢复参数
|
||
const savedParams = sessionStorage.getItem('spotify_callback_params')
|
||
|
||
if (savedParams) {
|
||
// 恢复 URL 参数供 spotifyService 处理
|
||
const currentUrl = new URL(window.location.href)
|
||
currentUrl.search = savedParams
|
||
window.history.replaceState({}, '', currentUrl.toString())
|
||
|
||
// 清理
|
||
sessionStorage.removeItem('spotify_callback_params')
|
||
}
|
||
|
||
// 处理授权
|
||
if (window.location.search.includes('code=')) {
|
||
await spotifyService.handleCallback()
|
||
}
|
||
})
|
||
```
|
||
|
||
## ✅ 优势
|
||
|
||
1. **兼容性好**
|
||
- 支持 Hash 模式路由
|
||
- 不需要服务器配置 SPA 支持
|
||
|
||
2. **用户体验流畅**
|
||
- 自动检测和处理回调
|
||
- 清晰的加载和成功提示
|
||
- 自动跳转回原页面
|
||
|
||
3. **安全可靠**
|
||
- State 参数验证(CSRF 保护)
|
||
- 参数临时存储,用后即删
|
||
- URL 清理,不暴露敏感信息
|
||
|
||
## 📋 部署步骤
|
||
|
||
1. **修改 Spotify Dashboard**
|
||
- 删除 `https://sports.rucky.cn/#/callback`
|
||
- 添加 `https://sports.rucky.cn/`
|
||
- 保存设置
|
||
|
||
2. **部署新代码**
|
||
```bash
|
||
# 代码已构建完成
|
||
rsync -avz --delete dist/ user@sports.rucky.cn:/var/www/sports.rucky.cn/
|
||
```
|
||
|
||
3. **清除缓存测试**
|
||
```javascript
|
||
localStorage.clear()
|
||
sessionStorage.clear()
|
||
```
|
||
|
||
## 🧪 测试流程
|
||
|
||
1. 访问 https://sports.rucky.cn/
|
||
2. 进入音乐律动页面 (#/music-rhythm)
|
||
3. 点击 Spotify 标签
|
||
4. 点击"连接 Spotify 账号"
|
||
5. 在 Spotify 页面授权
|
||
6. 应该看到:
|
||
- ✅ 返回到首页(带 code 参数)
|
||
- ✅ 自动跳转到 #/callback
|
||
- ✅ 显示"正在处理授权..."
|
||
- ✅ 显示"授权成功!"
|
||
- ✅ 自动跳转回音乐律动页面
|
||
- ✅ Spotify 功能正常使用
|
||
|
||
## 🔍 调试
|
||
|
||
如果有问题,检查浏览器控制台:
|
||
|
||
```javascript
|
||
// 应该看到以下日志:
|
||
"✅ Spotify OAuth callback detected!"
|
||
"Code: AQBTrOWWZ8883ozZ1RD..."
|
||
"State: RxEHF89uqI2Y0YFR"
|
||
"✅ Processing Spotify OAuth callback from sessionStorage"
|
||
```
|
||
|
||
## 📝 注意事项
|
||
|
||
1. **必须使用根路径**
|
||
- Spotify 不支持 hash 格式的 redirect_uri
|
||
- 只能使用 `https://sports.rucky.cn/`
|
||
|
||
2. **Hash 模式的限制**
|
||
- URL 会短暂显示 code 参数
|
||
- 需要额外的跳转步骤
|
||
|
||
3. **sessionStorage 的作用**
|
||
- 临时保存参数
|
||
- 跨路由传递数据
|
||
- 用后自动清理
|
||
|
||
## ✅ 问题已解决
|
||
|
||
- ✅ 支持 Hash 模式路由
|
||
- ✅ 正确处理 Spotify 回调
|
||
- ✅ 完整的授权流程
|
||
- ✅ 良好的用户体验
|
||
|
||
现在部署新代码,就能完美使用了!🎉
|