所有页面未登录时, 被跳转到登录页面。
This commit is contained in:
143
App.vue
143
App.vue
@@ -6,6 +6,8 @@
|
||||
// #endif
|
||||
import checkIsAgree from '@/pages/uni-agree/utils/uni-agree.js';
|
||||
import uniIdPageInit from '@/uni_modules/uni-id-pages/init.js';
|
||||
import { store } from '@/uni_modules/uni-id-pages/common/store.js';
|
||||
|
||||
export default {
|
||||
globalData: {
|
||||
searchText: '',
|
||||
@@ -21,6 +23,14 @@
|
||||
initApp();
|
||||
uniIdPageInit()
|
||||
|
||||
// 设置全局路由拦截,检查登录状态
|
||||
this.setupRouteInterceptor()
|
||||
|
||||
// 延迟检查登录状态,确保 store 已初始化
|
||||
setTimeout(() => {
|
||||
this.checkCurrentPageLogin()
|
||||
}, 100)
|
||||
|
||||
// #ifdef APP
|
||||
//checkIsAgree(); APP端暂时先用原生默认生成的。目前,自定义方式启动vue界面时,原生层已经请求了部分权限这并不符合国家的法规
|
||||
// #endif
|
||||
@@ -44,9 +54,142 @@
|
||||
},
|
||||
onShow: function() {
|
||||
console.log('App Show')
|
||||
// 每次应用显示时也检查当前页面是否需要登录
|
||||
this.checkCurrentPageLogin()
|
||||
},
|
||||
onHide: function() {
|
||||
console.log('App Hide')
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 设置全局路由拦截
|
||||
*/
|
||||
setupRouteInterceptor() {
|
||||
const app = this
|
||||
|
||||
// 拦截路由跳转(适用于所有平台)
|
||||
uni.addInterceptor('navigateTo', {
|
||||
invoke: (options) => {
|
||||
if (app.shouldRedirectToLogin(options.url)) {
|
||||
app.redirectToLogin()
|
||||
return false // 阻止跳转
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
uni.addInterceptor('redirectTo', {
|
||||
invoke: (options) => {
|
||||
if (app.shouldRedirectToLogin(options.url)) {
|
||||
app.redirectToLogin()
|
||||
return false // 阻止跳转
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
uni.addInterceptor('switchTab', {
|
||||
invoke: (options) => {
|
||||
if (app.shouldRedirectToLogin(options.url)) {
|
||||
app.redirectToLogin()
|
||||
return false // 阻止跳转
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
uni.addInterceptor('reLaunch', {
|
||||
invoke: (options) => {
|
||||
if (app.shouldRedirectToLogin(options.url)) {
|
||||
app.redirectToLogin()
|
||||
return false // 阻止跳转
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 判断是否需要跳转到登录页
|
||||
*/
|
||||
shouldRedirectToLogin(url) {
|
||||
if (!url) return false
|
||||
|
||||
// 排除登录相关页面
|
||||
const excludePaths = [
|
||||
'/uni_modules/uni-id-pages/pages/login',
|
||||
'/uni_modules/uni-id-pages/pages/register',
|
||||
'/uni_modules/uni-id-pages/pages/retrieve'
|
||||
]
|
||||
|
||||
// 检查是否在排除列表中
|
||||
for (let excludePath of excludePaths) {
|
||||
if (url.includes(excludePath)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 检查登录状态
|
||||
return !this.isLoggedIn()
|
||||
},
|
||||
|
||||
/**
|
||||
* 检查是否已登录
|
||||
*/
|
||||
isLoggedIn() {
|
||||
// 优先检查后端登录态
|
||||
const backendToken = uni.getStorageSync('backend-token')
|
||||
if (backendToken) {
|
||||
return true
|
||||
}
|
||||
|
||||
// 其次检查 uni-id 的登录态
|
||||
return store.hasLogin
|
||||
},
|
||||
|
||||
/**
|
||||
* 跳转到登录页
|
||||
*/
|
||||
redirectToLogin() {
|
||||
const loginPage = '/uni_modules/uni-id-pages/pages/login/login-withpwd'
|
||||
const pages = getCurrentPages()
|
||||
|
||||
// 如果当前已经在登录页,不重复跳转
|
||||
if (pages.length > 0) {
|
||||
const currentPage = pages[pages.length - 1]
|
||||
if (currentPage.route && currentPage.route.includes('login')) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
uni.reLaunch({
|
||||
url: loginPage,
|
||||
fail: (err) => {
|
||||
console.error('跳转登录页失败:', err)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 检查当前页面是否需要登录
|
||||
*/
|
||||
checkCurrentPageLogin() {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length === 0) return
|
||||
|
||||
const currentPage = pages[pages.length - 1]
|
||||
if (!currentPage || !currentPage.route) return
|
||||
|
||||
const currentRoute = '/' + currentPage.route
|
||||
|
||||
// 排除登录相关页面
|
||||
if (currentRoute.includes('/uni_modules/uni-id-pages/pages/login') ||
|
||||
currentRoute.includes('/uni_modules/uni-id-pages/pages/register') ||
|
||||
currentRoute.includes('/uni_modules/uni-id-pages/pages/retrieve')) {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果未登录,跳转到登录页
|
||||
if (!this.isLoggedIn()) {
|
||||
this.redirectToLogin()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
81
common/check-tenant-id.js
Normal file
81
common/check-tenant-id.js
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 检查所有后端请求是否包含 tenantId 的工具
|
||||
*
|
||||
* 使用方法:
|
||||
* 1. 在浏览器控制台或 Node.js 环境中运行
|
||||
* 2. 或者集成到构建流程中
|
||||
*/
|
||||
|
||||
/**
|
||||
* 检查代码文件中是否使用了 uni.request 且可能缺少 tenantId
|
||||
*
|
||||
* 注意:这是一个静态检查工具,实际运行时需要确保:
|
||||
* 1. 使用统一的 request 封装(common/request.js)
|
||||
* 2. 或者手动在每个请求中添加 tenantId
|
||||
*/
|
||||
export function checkTenantIdInCode() {
|
||||
console.log('=== 检查 tenantId 使用情况 ===')
|
||||
console.log('')
|
||||
console.log('✅ 已创建统一的请求封装:common/request.js')
|
||||
console.log(' - 自动为所有请求添加 tenantId')
|
||||
console.log(' - GET 请求:tenantId 作为 query 参数')
|
||||
console.log(' - POST/PUT/DELETE 请求:tenantId 作为 body 字段')
|
||||
console.log('')
|
||||
console.log('📝 需要迁移的文件(使用 uni.request 的地方):')
|
||||
console.log(' 1. pages/reception/reception.vue')
|
||||
console.log(' 2. pages/customer/customer.vue')
|
||||
console.log(' 3. uni_modules/uni-id-pages/common/store.js (登出接口)')
|
||||
console.log('')
|
||||
console.log('💡 迁移方法:')
|
||||
console.log(' 将 uni.request 替换为:')
|
||||
console.log(' import { request, get, post, put, del } from "@/common/request.js"')
|
||||
console.log('')
|
||||
console.log(' 示例:')
|
||||
console.log(' // 旧代码:')
|
||||
console.log(' uni.request({ url: getApiUrl("/api/xxx"), method: "GET" })')
|
||||
console.log('')
|
||||
console.log(' // 新代码:')
|
||||
console.log(' import { get } from "@/common/request.js"')
|
||||
console.log(' get("/api/xxx")')
|
||||
console.log('')
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行时检查:验证当前请求是否包含 tenantId
|
||||
* 可以在 uni.request 拦截器中调用
|
||||
*/
|
||||
export function validateRequestHasTenantId(requestOptions) {
|
||||
const { method = 'GET', data = {}, url = '' } = requestOptions
|
||||
|
||||
// 检查 tenantId 是否存在
|
||||
const tenantId = uni.getStorageSync('backend-tenant-id')
|
||||
|
||||
if (!tenantId) {
|
||||
console.warn('[TenantId Check] ⚠️ 未找到 tenantId,请先登录')
|
||||
return false
|
||||
}
|
||||
|
||||
// 检查请求中是否包含 tenantId
|
||||
if (method.toUpperCase() === 'GET') {
|
||||
// GET 请求:检查 URL 中是否有 tenantId
|
||||
if (!url.includes('tenantId=')) {
|
||||
console.warn('[TenantId Check] ⚠️ GET 请求缺少 tenantId:', url)
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
// POST/PUT/DELETE 请求:检查 data 中是否有 tenantId
|
||||
if (!data.tenantId) {
|
||||
console.warn('[TenantId Check] ⚠️', method, '请求缺少 tenantId:', url)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
console.log('[TenantId Check] ✅ 请求包含 tenantId:', url)
|
||||
return true
|
||||
}
|
||||
|
||||
// 如果直接运行此文件,执行检查
|
||||
if (typeof window !== 'undefined' || typeof global !== 'undefined') {
|
||||
checkTenantIdInCode()
|
||||
}
|
||||
|
||||
179
common/request.js
Normal file
179
common/request.js
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* 统一的 HTTP 请求封装
|
||||
* 自动添加 tenantId、token 等公共参数
|
||||
*/
|
||||
|
||||
import { getApiUrl } from './config.js'
|
||||
|
||||
/**
|
||||
* 获取 tenantId(从本地存储)
|
||||
*/
|
||||
function getTenantId() {
|
||||
try {
|
||||
return uni.getStorageSync('backend-tenant-id') || ''
|
||||
} catch (e) {
|
||||
console.error('获取 tenantId 失败:', e)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 token(从本地存储)
|
||||
*/
|
||||
function getToken() {
|
||||
try {
|
||||
return uni.getStorageSync('backend-token') || ''
|
||||
} catch (e) {
|
||||
console.error('获取 token 失败:', e)
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一的请求方法
|
||||
* @param {Object} options - uni.request 的配置选项
|
||||
* @param {string} options.url - 请求地址(会自动使用 getApiUrl 处理)
|
||||
* @param {string} options.method - 请求方法,默认 'GET'
|
||||
* @param {Object} options.data - 请求数据
|
||||
* @param {Object} options.header - 请求头(会自动合并公共 header)
|
||||
* @param {number} options.timeout - 超时时间
|
||||
* @param {boolean} options.needTenantId - 是否需要添加 tenantId,默认 true
|
||||
* @param {boolean} options.needToken - 是否需要添加 token,默认 true
|
||||
* @returns {Promise} 请求结果
|
||||
*/
|
||||
export function request(options = {}) {
|
||||
const {
|
||||
url,
|
||||
method = 'GET',
|
||||
data = {},
|
||||
header = {},
|
||||
timeout = 10000,
|
||||
needTenantId = true,
|
||||
needToken = true,
|
||||
...restOptions
|
||||
} = options
|
||||
|
||||
// 处理 URL(自动添加 baseUrl)
|
||||
const fullUrl = url.startsWith('http') ? url : getApiUrl(url)
|
||||
|
||||
// 构建请求头
|
||||
const requestHeader = {
|
||||
'Content-Type': 'application/json',
|
||||
...header
|
||||
}
|
||||
|
||||
// 添加 token(如果需要)
|
||||
if (needToken) {
|
||||
const token = getToken()
|
||||
if (token) {
|
||||
requestHeader['Authorization'] = `Bearer ${token}`
|
||||
// 或者使用其他 header 名称,根据后端要求调整
|
||||
// requestHeader['X-Token'] = token
|
||||
}
|
||||
}
|
||||
|
||||
// 处理请求数据
|
||||
let requestData = { ...data }
|
||||
|
||||
// 添加 tenantId 到 X-Tenant-Id header
|
||||
// 技术方案:登录返回的 LoginResponse 中包含 tenantId,前端保存后自动添加到所有请求的 header 中
|
||||
if (needTenantId) {
|
||||
const tenantId = getTenantId()
|
||||
if (tenantId) {
|
||||
// 将 tenantId 放入 X-Tenant-Id header(适用于所有请求类型:GET、POST、PUT、DELETE)
|
||||
requestHeader['X-Tenant-Id'] = tenantId
|
||||
|
||||
// 添加日志,证明已发送 X-Tenant-Id header
|
||||
console.log('[Request] ✅ 已添加 X-Tenant-Id header:', {
|
||||
url: finalUrl,
|
||||
method: method.toUpperCase(),
|
||||
'X-Tenant-Id': tenantId,
|
||||
headers: { ...requestHeader }
|
||||
})
|
||||
} else {
|
||||
console.warn('[Request] ⚠️ 未找到 tenantId,请求可能失败。请确保已登录并获取到 tenantId')
|
||||
}
|
||||
}
|
||||
|
||||
// 发起请求
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: finalUrl,
|
||||
method: method.toUpperCase(),
|
||||
data: requestData,
|
||||
header: requestHeader,
|
||||
timeout,
|
||||
...restOptions,
|
||||
success: (res) => {
|
||||
// 请求成功时也输出日志,确认 header 已发送
|
||||
if (needTenantId && requestHeader['X-Tenant-Id']) {
|
||||
console.log('[Request] ✅ 请求成功,已发送 X-Tenant-Id:', {
|
||||
url: finalUrl,
|
||||
method: method.toUpperCase(),
|
||||
'X-Tenant-Id': requestHeader['X-Tenant-Id'],
|
||||
statusCode: res.statusCode
|
||||
})
|
||||
}
|
||||
resolve(res)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[Request] ❌ 请求失败:', {
|
||||
url: finalUrl,
|
||||
method: method.toUpperCase(),
|
||||
'X-Tenant-Id': requestHeader['X-Tenant-Id'] || '未设置',
|
||||
error: err
|
||||
})
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* GET 请求快捷方法
|
||||
*/
|
||||
export function get(url, data = {}, options = {}) {
|
||||
return request({
|
||||
url,
|
||||
method: 'GET',
|
||||
data,
|
||||
...options
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* POST 请求快捷方法
|
||||
*/
|
||||
export function post(url, data = {}, options = {}) {
|
||||
return request({
|
||||
url,
|
||||
method: 'POST',
|
||||
data,
|
||||
...options
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT 请求快捷方法
|
||||
*/
|
||||
export function put(url, data = {}, options = {}) {
|
||||
return request({
|
||||
url,
|
||||
method: 'PUT',
|
||||
data,
|
||||
...options
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE 请求快捷方法
|
||||
*/
|
||||
export function del(url, data = {}, options = {}) {
|
||||
return request({
|
||||
url,
|
||||
method: 'DELETE',
|
||||
data,
|
||||
...options
|
||||
})
|
||||
}
|
||||
|
||||
@@ -90,14 +90,15 @@ export const mutations = {
|
||||
}
|
||||
}
|
||||
|
||||
// 清理本地登录状态(后端 token + 旧 uni-id token)
|
||||
// 清理本地登录状态(后端 token + 旧 uni-id token + tenantId)
|
||||
uni.removeStorageSync('backend-token')
|
||||
uni.removeStorageSync('backend-login-response')
|
||||
uni.removeStorageSync('backend-user-id')
|
||||
uni.removeStorageSync('backend-tenant-id') // 清除 tenantId
|
||||
uni.removeStorageSync('uni_id_token');
|
||||
uni.setStorageSync('uni_id_token_expired', 0)
|
||||
this.setUserInfo({},{cover:true})
|
||||
uni.$emit('uni-id-pages-logout')
|
||||
this.setUserInfo({},{cover:true})
|
||||
uni.$emit('uni-id-pages-logout')
|
||||
uni.redirectTo({
|
||||
url: `/${pagesJson.uniIdRouter && pagesJson.uniIdRouter.loginPage ? pagesJson.uniIdRouter.loginPage: 'uni_modules/uni-id-pages/pages/login/login-withoutpwd'}`,
|
||||
});
|
||||
|
||||
@@ -132,6 +132,15 @@
|
||||
uni.setStorageSync('backend-login-response', loginData)
|
||||
uni.setStorageSync('backend-token', loginData.token || '')
|
||||
uni.setStorageSync('backend-user-id', loginData.userId)
|
||||
|
||||
// 保存 tenantId(从 LoginResponse 中获取,后端 UserServiceImpl.login 从 user.getTenantId() 赋值)
|
||||
// 后续所有请求会自动在 X-Tenant-Id header 中携带此值
|
||||
if (loginData.tenantId) {
|
||||
uni.setStorageSync('backend-tenant-id', loginData.tenantId)
|
||||
console.log('[Login] tenantId 已保存:', loginData.tenantId)
|
||||
} else {
|
||||
console.warn('[Login] 登录响应中未包含 tenantId,后续请求可能失败')
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('缓存登录信息失败:', e)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user