-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreset-password.html
More file actions
172 lines (156 loc) · 7.75 KB
/
Copy pathreset-password.html
File metadata and controls
172 lines (156 loc) · 7.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>重置密码 - 养虾助手</title>
<script src="https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2"></script>
<style>
body { font-family: system-ui, -apple-system, sans-serif; max-width: 600px; margin: 40px auto; padding: 20px; text-align: center; }
.container { max-width: 400px; margin: 0 auto; padding: 30px; border-radius: 8px; box-shadow: 0 0 15px rgba(0,0,0,0.08); }
h2 { margin-bottom: 20px; color: #333; }
input { width: 100%; padding: 12px; margin: 10px 0; border: 1px solid #ddd; border-radius: 4px; font-size: 16px; box-sizing: border-box; }
button { width: 100%; background: #005fcc; color: white; padding: 12px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px; transition: background 0.3s; }
button:hover:not(:disabled) { background: #0045a3; }
button:disabled { background: #a0c4e8; cursor: not-allowed; }
.msg { margin-top: 15px; font-weight: bold; min-height: 20px; }
.success { color: green; }
.error { color: red; }
</style>
</head>
<body>
<div class="container">
<h2>🔐 重置密码</h2>
<div id="status">正在验证链接,请稍候...</div>
<div id="form" style="display:none;">
<input type="password" id="password" placeholder="请输入新密码(至少6位)">
<button onclick="resetPassword()" id="resetBtn">确认修改</button>
<div id="msg" class="msg"></div>
</div>
</div>
<script>
const sbUrl = 'https://apumkkayconibhkaawdn.supabase.co';
const sbKey = 'sb_publishable_Tn8FsSUL4iDqUsNQGzos6Q_6zMKytC5';
let sbClient = null;
function setStatus(text, isError = false) {
const el = document.getElementById('status');
if (el) { el.innerHTML = text; el.style.color = isError ? 'red' : '#333'; }
}
function parseQueryParams() {
const params = new URLSearchParams(window.location.search);
return { token_hash: params.get('token_hash'), type: params.get('type') };
}
function parseHashParams() {
const hash = window.location.hash.substring(1);
const params = new URLSearchParams(hash);
return {
access_token: params.get('access_token'),
refresh_token: params.get('refresh_token'),
type: params.get('type')
};
}
async function init() {
try {
let clientCreator = null;
if (typeof createClient === 'function') {
clientCreator = createClient;
} else if (window.supabase && typeof window.supabase.createClient === 'function') {
clientCreator = window.supabase.createClient;
} else if (window.supabase && window.supabase.auth) {
sbClient = window.supabase;
} else {
setStatus('❌ 系统加载失败,请刷新页面重试', true);
return;
}
if (clientCreator) sbClient = clientCreator(sbUrl, sbKey);
if (!sbClient || !sbClient.auth) {
setStatus('❌ 系统加载失败,请刷新页面重试', true);
return;
}
setStatus('正在验证链接...');
// 先检查hash中是否有错误信息(Supabase自动处理后返回的错误)
const hashParams = parseHashParams();
const hashError = new URLSearchParams(window.location.hash.substring(1)).get('error_description');
if (hashError) {
setStatus('❌ ' + decodeURIComponent(hashError), true);
return;
}
// PKCE流程
const queryParams = parseQueryParams();
if (queryParams.token_hash) {
if (queryParams.type !== 'recovery') {
setStatus('❌ 链接类型错误,请重新发送重置邮件', true);
return;
}
const { data, error } = await sbClient.auth.verifyOtp({ token_hash: queryParams.token_hash, type: 'recovery' });
if (error) { setStatus('❌ ' + error.message, true); return; }
if (!data || !data.session) { setStatus('❌ 验证失败,链接可能已过期', true); return; }
showForm();
return;
}
// Implicit流程
if (hashParams.access_token) {
if (hashParams.type !== 'recovery') {
setStatus('❌ 链接类型错误,请重新发送重置邮件', true);
return;
}
await new Promise(resolve => setTimeout(resolve, 500));
const { data, error } = await sbClient.auth.getSession();
if (error) { setStatus('❌ ' + error.message, true); return; }
if (!data || !data.session) {
const setResult = await sbClient.auth.setSession({
access_token: hashParams.access_token,
refresh_token: hashParams.refresh_token || ''
});
if (setResult.error) { setStatus('❌ ' + setResult.error.message, true); return; }
if (!setResult.data || !setResult.data.session) { setStatus('❌ 验证失败,链接可能已过期', true); return; }
}
showForm();
return;
}
setStatus('❌ 链接无效,请从邮件中点击完整链接打开', true);
} catch (err) {
setStatus('❌ 验证失败,请刷新页面重试', true);
console.error(err);
}
}
function showForm() {
document.getElementById('status').style.display = 'none';
document.getElementById('form').style.display = 'block';
}
async function resetPassword() {
const btn = document.getElementById('resetBtn');
const msgDiv = document.getElementById('msg');
const password = document.getElementById('password').value.trim();
if (password.length < 6) {
msgDiv.innerHTML = '<span class="error">⚠️ 密码至少需要6位</span>';
return;
}
btn.disabled = true;
btn.textContent = '正在修改...';
msgDiv.innerHTML = '';
try {
const { data, error } = await sbClient.auth.updateUser({ password });
if (error) {
msgDiv.innerHTML = '<span class="error">❌ 修改失败:' + error.message + '</span>';
btn.disabled = false;
btn.textContent = '确认修改';
return;
}
document.getElementById('form').style.display = 'none';
document.getElementById('status').style.display = 'block';
setStatus('✅ 密码修改成功!请返回APP重新登录。');
} catch (err) {
msgDiv.innerHTML = '<span class="error">❌ 修改失败:' + err.message + '</span>';
btn.disabled = false;
btn.textContent = '确认修改';
}
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
</script>
</body>
</html>