feat(登录): 实现登录策略和路由拦截功能
添加登录相关配置文件和页面,包括登录策略配置、注册页面和路由拦截逻辑 移除旧的登录相关代码和配置,使用新的登录策略实现 在用户store中添加hasLogin计算属性用于检查登录状态 优化路由拦截器逻辑,支持白名单和黑名单策略
This commit is contained in:
3
env/.env
vendored
3
env/.env
vendored
@@ -8,9 +8,6 @@ VITE_WX_APPID = 'wxa2abb91f64032a2b'
|
||||
# https://uniapp.dcloud.net.cn/collocation/manifest.html#h5-router
|
||||
VITE_APP_PUBLIC_BASE=/
|
||||
|
||||
# 登录页面
|
||||
VITE_LOGIN_URL = '/pages/login/index'
|
||||
|
||||
# 后台请求地址
|
||||
VITE_SERVER_BASEURL = 'https://ukw0y1.laf.run'
|
||||
# 后台上传地址
|
||||
|
||||
15
src/App.vue
15
src/App.vue
@@ -1,21 +1,20 @@
|
||||
<script setup lang="ts">
|
||||
import { onHide, onLaunch, onShow } from '@dcloudio/uni-app'
|
||||
import { navigateToInterceptor } from '@/router/interceptor'
|
||||
|
||||
import { tabbarStore } from './tabbar/store'
|
||||
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
|
||||
|
||||
onLaunch((options) => {
|
||||
// 处理直接进入页面路由的情况:如h5直接输入路由、微信小程序分享后进入等
|
||||
// https://github.com/unibest-tech/unibest/issues/192
|
||||
console.log('App Launch', options)
|
||||
if (options?.path) {
|
||||
navigateToInterceptor.invoke({ url: `/${options.path}` })
|
||||
}
|
||||
else {
|
||||
navigateToInterceptor.invoke({ url: '/' })
|
||||
}
|
||||
console.log('App Launch options: ', options)
|
||||
const gotoPath = options?.path || ''
|
||||
|
||||
navigateToInterceptor.invoke({ url: gotoPath })
|
||||
|
||||
// 处理直接进入路由非首页时,tabbarIndex 不正确的问题
|
||||
tabbarStore.setAutoCurIdx(options.path)
|
||||
tabbarStore.setAutoCurIdx(gotoPath)
|
||||
})
|
||||
onShow((options) => {
|
||||
console.log('App Show', options)
|
||||
|
||||
15
src/login/README.md
Normal file
15
src/login/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# 登录 说明
|
||||
|
||||
## 登录 2种策略
|
||||
- 白名单策略
|
||||
- 黑名单策略
|
||||
|
||||
### 白名单策略
|
||||
进入任何页面都需要登录,只有进入到白名单中的页面,才不需要登录。默认进入应用需要先去登录页。
|
||||
|
||||
比如大部分2C的应用,美团、今日头条、抖音等,都可以直接浏览,只有去个人中心,或者点赞、评论、分享等操作,才需要登录。
|
||||
|
||||
### 黑名单策略
|
||||
进入任何页面都不需要登录,只有进入到黑名单中的页面/或者页面中某些动作需要登录,才需要登录。
|
||||
|
||||
比如大部分2B和后台管理类的应用,比如企业微信、钉钉、飞书、内部报表系统、CMS系统等,都需要登录,只有登录后,才能使用。
|
||||
13
src/login/config.ts
Normal file
13
src/login/config.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
export const LOGIN_STRATEGY_MAP = {
|
||||
BLACKLIST: 'BLACKLIST', // 黑名单策略,默认可以进入APP
|
||||
WHITELIST: 'WHITELIST', // 白名单策略,默认不可以进入APP,需要强制登录
|
||||
}
|
||||
// 登录策略,默认使用黑名单策略,即默认不需要登录就可以访问
|
||||
export const LOGIN_STRATEGY = LOGIN_STRATEGY_MAP.WHITELIST
|
||||
|
||||
export const LOGIN_PAGE_LIST = ['/login/login', '/login/register']
|
||||
|
||||
// 排除在外的列表,白名单策略指白名单列表,黑名单策略指黑名单列表
|
||||
export const EXCLUDE_LIST = [
|
||||
'/xxx/index',
|
||||
]
|
||||
@@ -72,6 +72,22 @@
|
||||
"style": {
|
||||
"navigationBarTitleText": "Vue Query 请求演示"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/login",
|
||||
"type": "page",
|
||||
"layout": "default",
|
||||
"style": {
|
||||
"navigationBarTitleText": "登录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/login/register",
|
||||
"type": "page",
|
||||
"layout": "default",
|
||||
"style": {
|
||||
"navigationBarTitleText": "注册"
|
||||
}
|
||||
}
|
||||
],
|
||||
"subPackages": [
|
||||
|
||||
19
src/pages/login/register.vue
Normal file
19
src/pages/login/register.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<route lang="jsonc" type="page">
|
||||
{
|
||||
"layout": "default",
|
||||
"style": {
|
||||
"navigationBarTitleText": "注册"
|
||||
}
|
||||
}
|
||||
</route>
|
||||
|
||||
<script lang="ts" setup>
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view>注册</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
//
|
||||
</style>
|
||||
@@ -6,54 +6,43 @@
|
||||
*/
|
||||
import { useUserStore } from '@/store'
|
||||
import { tabbarStore } from '@/tabbar/store'
|
||||
import { needLoginPages as _needLoginPages, getLastPage, getNeedLoginPages } from '@/utils'
|
||||
|
||||
// TODO Check
|
||||
const loginRoute = import.meta.env.VITE_LOGIN_URL
|
||||
|
||||
function isLogined() {
|
||||
const userStore = useUserStore()
|
||||
return !!userStore.userInfo.username
|
||||
}
|
||||
|
||||
const isDev = import.meta.env.DEV
|
||||
import { getLastPage } from '@/utils'
|
||||
import { EXCLUDE_LIST, LOGIN_PAGE_LIST } from '../login/config'
|
||||
|
||||
// 黑名单登录拦截器 - (适用于大部分页面不需要登录,少部分页面需要登录)
|
||||
export const navigateToInterceptor = {
|
||||
// 注意,这里的url是 '/' 开头的,如 '/pages/index/index',跟 'pages.json' 里面的 path 不同
|
||||
// 增加对相对路径的处理,BY 网友 @ideal
|
||||
invoke({ url }: { url: string }) {
|
||||
// console.log(url) // /pages/route-interceptor/index?name=feige&age=30
|
||||
console.log(url) // /pages/route-interceptor/index?name=feige&age=30
|
||||
let path = url.split('?')[0]
|
||||
|
||||
// 处理相对路径
|
||||
if (!path.startsWith('/')) {
|
||||
const currentPath = getLastPage().route
|
||||
const currentPath = getLastPage()?.route || ''
|
||||
const normalizedCurrentPath = currentPath.startsWith('/') ? currentPath : `/${currentPath}`
|
||||
const baseDir = normalizedCurrentPath.substring(0, normalizedCurrentPath.lastIndexOf('/'))
|
||||
path = `${baseDir}/${path}`
|
||||
}
|
||||
|
||||
let needLoginPages: string[] = []
|
||||
// 为了防止开发时出现BUG,这里每次都获取一下。生产环境可以移到函数外,性能更好
|
||||
if (isDev) {
|
||||
needLoginPages = getNeedLoginPages()
|
||||
}
|
||||
else {
|
||||
needLoginPages = _needLoginPages
|
||||
}
|
||||
const isNeedLogin = needLoginPages.includes(path)
|
||||
if (!isNeedLogin) {
|
||||
return true
|
||||
}
|
||||
const hasLogin = isLogined()
|
||||
if (hasLogin) {
|
||||
return true
|
||||
if (LOGIN_PAGE_LIST.includes(path)) {
|
||||
console.log('000')
|
||||
return
|
||||
}
|
||||
|
||||
tabbarStore.restorePrevIdx()
|
||||
const redirectRoute = `${loginRoute}?redirect=${encodeURIComponent(url)}`
|
||||
uni.navigateTo({ url: redirectRoute })
|
||||
return false
|
||||
|
||||
console.log('拦截器中得到的 path:', path)
|
||||
const userStore = useUserStore()
|
||||
|
||||
if (userStore.hasLogin || [...EXCLUDE_LIST, ...LOGIN_PAGE_LIST].includes(path)) {
|
||||
console.log('111')
|
||||
uni.navigateTo({ url: path })
|
||||
return
|
||||
}
|
||||
console.log('222')
|
||||
const redirectUrl = `/login/login?redirect=${encodeURIComponent(path)}`
|
||||
uni.navigateTo({ url: redirectUrl })
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ export const useUserStore = defineStore(
|
||||
getUserInfo,
|
||||
setUserAvatar,
|
||||
logout,
|
||||
hasLogin: computed(() => !!userInfo.value.token),
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -110,18 +110,6 @@ export function getCurrentPageI18nKey() {
|
||||
return currPage.style.navigationBarTitleText
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到所有的需要登录的 pages,包括主包和分包的
|
||||
* 只得到 path 数组
|
||||
*/
|
||||
export const getNeedLoginPages = (): string[] => getAllPages('needLogin').map(page => page.path)
|
||||
|
||||
/**
|
||||
* 得到所有的需要登录的 pages,包括主包和分包的
|
||||
* 只得到 path 数组
|
||||
*/
|
||||
export const needLoginPages: string[] = getAllPages('needLogin').map(page => page.path)
|
||||
|
||||
/**
|
||||
* 根据微信小程序当前环境,判断应该获取的 baseUrl
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user