在 uni-app
中實現用戶登錄一次后在 token
過期前一直免登錄的功能,可以通過以下幾個關鍵步驟實現:本地持久化存儲 Token、使用請求與響應攔截器自動處理 Token 刷新、以及在 App.vue
中結合 pages.json
設置登錄狀態跳轉邏輯。
? 一、pages.json
?配置說明
pages.json
是 uni-app
的全局配置文件,用于定義頁面路徑、窗口樣式、啟動頁等。雖然它不直接支持登錄狀態判斷,但可以配合 App.vue
的 onLaunch
生命周期實現登錄狀態的控制。
示例?pages.json
?配置:
{"pages": [{"path": "pages/home/home","style": {"navigationBarTitleText": "主頁"}},{"path": "pages/login/login","style": {"navigationBarTitleText": "登錄"}}],"globalStyle": {"navigationBarTitleText": "uni-app","navigationBarBackgroundColor": "#ffffff","backgroundColor": "#ffffff"},"window": {"navigationBarTitleText": "uni-app"},"tabBar": {"list": [{"pagePath": "pages/home/home","text": "主頁"},{"pagePath": "pages/user/user","text": "我的"}]}
}
?? 注意:
pages.json
中 第一個頁面 是默認啟動頁(即 App 啟動時進入的第一個頁面)。我們會在App.vue
中動態決定跳轉哪一個頁面。
? 二、App.vue 中實現登錄狀態判斷
App.vue
的 onLaunch
生命周期是應用啟動時的入口,適合在此判斷用戶是否已經登錄(通過 Token 是否存在和是否過期),從而決定是否跳轉到登錄頁或主頁。
示例代碼(App.vue):
<script>
export default {onLaunch() {// 檢查本地是否存在有效的 tokenconst token = uni.getStorageSync('token');const expireTime = uni.getStorageSync('tokenExpireTime');if (token && Date.now() < expireTime) {// token 有效,跳轉到主頁uni.reLaunch({url: '/pages/home/home'});} else {// token 無效或不存在,跳轉到登錄頁uni.reLaunch({url: '/pages/login/login'});}}
}
</script>
? 三、登錄與 Token 存儲邏輯
在登錄成功后,需將 token
和 refreshToken
存入本地存儲,并記錄 token
的過期時間。
示例代碼(login.vue):
<script>
export default {methods: {async handleLogin() {const res = await uni.request({url: 'https://api.example.com/login',method: 'POST',data: {username: this.username,password: this.password}});const { token, refreshToken, expiresIn } = res.data;// 存儲 token 和 refresh tokenuni.setStorageSync('token', token);uni.setStorageSync('refreshToken', refreshToken);// 計算 token 過期時間(單位:毫秒)const expireTime = Date.now() + expiresIn * 1000;uni.setStorageSync('tokenExpireTime', expireTime);// 登錄成功后跳轉到主頁uni.reLaunch({url: '/pages/home/home'});}}
}
</script>
? 四、請求與響應攔截器自動處理 Token
通過封裝請求攔截器和響應攔截器,可以實現自動添加 token
到請求頭、以及在 token
過期時自動刷新。
請求攔截器(添加 token)
uni.addInterceptor('request', {invoke(args) {const token = uni.getStorageSync('token');if (token) {args.header = {...args.header,Authorization: `Bearer ${token}`};}return args;}
});
響應攔截器(token 刷新)
uni.addInterceptor('request', {response: (res) => {if (res.statusCode === 401) {// token 過期,嘗試刷新return refreshToken().then((newToken) => {uni.setStorageSync('token', newToken.token);uni.setStorageSync('tokenExpireTime', Date.now() + newToken.expiresIn * 1000);return uni.request(res.config); // 重新發送原請求}).catch(() => {uni.reLaunch({ url: '/pages/login/login' }); // 刷新失敗則跳轉登錄頁});}return res;}
});
refreshToken()
?函數示例:
async function refreshToken() {const refreshToken = uni.getStorageSync('refreshToken');const res = await uni.request({url: 'https://api.example.com/refresh-token',method: 'POST',data: { refreshToken }});return res.data;
}
? 五、Token 即將過期時主動刷新
在每次請求前檢查 token
是否即將過期,提前刷新以避免請求失敗。
function isTokenExpired() {const now = Date.now();const expireTime = uni.getStorageSync('tokenExpireTime');return now >= expireTime;
}uni.addInterceptor('request', {invoke(args) {if (isTokenExpired()) {return refreshToken().then((newToken) => {uni.setStorageSync('token', newToken.token);uni.setStorageSync('tokenExpireTime', Date.now() + newToken.expiresIn * 1000);return uni.request(args); // 重新發送請求}).catch(() => {uni.reLaunch({ url: '/pages/login/login' });});}return args;}
});
? 六、安全建議(可選)
- 加密存儲:使用?
AES
?或?RSA
?加密敏感數據(如?token
)。 - Token 鎖機制:防止多個請求同時觸發刷新。
- 清理本地存儲:用戶登出時清除?
token
?和?refreshToken
。 - 敏感信息不要明文存儲。
? 七、總結
步驟 | 內容 |
---|---|
1.?pages.json | 配置頁面路徑和啟動頁 |
2.?App.vue | 使用?onLaunch ?判斷登錄狀態 |
3. 登錄邏輯 | 登錄成功后存儲 token 和 refresh token |
4. 請求攔截器 | 自動添加 token 到請求頭 |
5. 響應攔截器 | 自動刷新 token 并重試請求 |
6. 主動刷新 token | 在請求前檢查 token 是否即將過期 |
通過以上完整流程,你可以實現用戶在 uni-app
中登錄一次后,在 token
過期前免登錄的功能。