Ver código fonte

feat(登录): 实现登录策略和路由拦截功能

添加登录相关配置文件和页面,包括登录策略配置、注册页面和路由拦截逻辑
移除旧的登录相关代码和配置,使用新的登录策略实现
在用户store中添加hasLogin计算属性用于检查登录状态
优化路由拦截器逻辑,支持白名单和黑名单策略
feige996 8 meses atrás
pai
commit
168a19fbca
9 arquivos alterados com 91 adições e 54 exclusões
  1. 0 3
      env/.env
  2. 7 8
      src/App.vue
  3. 15 0
      src/login/README.md
  4. 13 0
      src/login/config.ts
  5. 16 0
      src/pages.json
  6. 19 0
      src/pages/login/register.vue
  7. 20 31
      src/router/interceptor.ts
  8. 1 0
      src/store/user.ts
  9. 0 12
      src/utils/index.ts

+ 0 - 3
env/.env

@@ -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'
 # 后台上传地址

+ 7 - 8
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 - 0
src/login/README.md

@@ -0,0 +1,15 @@
+# 登录 说明
+
+## 登录 2种策略
+- 白名单策略
+- 黑名单策略
+
+### 白名单策略
+进入任何页面都需要登录,只有进入到白名单中的页面,才不需要登录。默认进入应用需要先去登录页。
+
+比如大部分2C的应用,美团、今日头条、抖音等,都可以直接浏览,只有去个人中心,或者点赞、评论、分享等操作,才需要登录。
+
+### 黑名单策略
+进入任何页面都不需要登录,只有进入到黑名单中的页面/或者页面中某些动作需要登录,才需要登录。
+
+比如大部分2B和后台管理类的应用,比如企业微信、钉钉、飞书、内部报表系统、CMS系统等,都需要登录,只有登录后,才能使用。

+ 13 - 0
src/login/config.ts

@@ -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',
+]

+ 16 - 0
src/pages.json

@@ -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 - 0
src/pages/login/register.vue

@@ -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>

+ 20 - 31
src/router/interceptor.ts

@@ -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 })
   },
 }
 

+ 1 - 0
src/store/user.ts

@@ -103,6 +103,7 @@ export const useUserStore = defineStore(
       getUserInfo,
       setUserAvatar,
       logout,
+      hasLogin: computed(() => !!userInfo.value.token),
     }
   },
   {

+ 0 - 12
src/utils/index.ts

@@ -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
  */