Procházet zdrojové kódy

Merge branch 'zhangtao' of gitadmin/tuoheng_pilot_web into develop

tags/v1.0.0
zhangtao před 2 roky
rodič
revize
9c34623d95
14 změnil soubory, kde provedl 278 přidání a 133 odebrání
  1. +2
    -1
      .env
  2. +7
    -2
      .env.development
  3. +6
    -1
      .env.localhost
  4. +6
    -1
      .env.production
  5. +7
    -2
      .env.test
  6. +1
    -0
      package.json
  7. +1
    -1
      src/api/login/index.js
  8. +26
    -16
      src/layout/components/Header/index.vue
  9. +4
    -4
      src/layout/index.vue
  10. +22
    -27
      src/router/guard/permission-guard.js
  11. +34
    -49
      src/store/modules/user.js
  12. +22
    -26
      src/utils/http/interceptors.js
  13. +91
    -0
      src/utils/oidc/index.js
  14. +49
    -3
      src/views/login/index.vue

+ 2
- 1
.env Zobrazit soubor

@@ -4,5 +4,6 @@ VITE_APP_TITLE = '智飞'
# 端口号
VITE_PORT = 3050

VITE_SERVER = "/pilot/admin"

VITE_SERVER = "/pilot/admin"
VITE_PLATFORM = "tuoheng-dsp-web"

+ 7
- 2
.env.development Zobrazit soubor

@@ -5,7 +5,12 @@ VITE_PUBLIC_PATH = '/'
VITE_APP_USE_MOCK = false

# proxy
VITE_PROXY = [["/api","http://192.168.11.11:9055"]]
VITE_PROXY = [["","http://192.168.11.11:7011"]]

# base api
VITE_APP_GLOB_BASE_API = '/api'
VITE_APP_GLOB_BASE_API = ''

VITE_AUTHORITY = 'http://oidc.dev.t-aaron.com'
VITE_CLIENT_ID = 'tuoheng-pilot-admin'
VITE_CLIENT_SECRET = 'WB0CZ1c6bZLiYP6jLtDFsA=='
VITE_REDIRECT_URI = 'http://192.168.11.11:7011/login'

+ 6
- 1
.env.localhost Zobrazit soubor

@@ -11,4 +11,9 @@ VITE_PROXY = [["/api-local","http://127.0.0.1:8002"],["/api-mock","http://127.0.
VITE_APP_GLOB_BASE_API = '/api-local'

# mock base api
VITE_APP_GLOB_BASE_API_MOCK = '/api-mock'
VITE_APP_GLOB_BASE_API_MOCK = '/api-mock'

VITE_AUTHORITY = 'http://oidc.dev.t-aaron.com'
VITE_CLIENT_ID = 'tuoheng-pilot-admin'
VITE_CLIENT_SECRET = 'WB0CZ1c6bZLiYP6jLtDFsA=='
VITE_REDIRECT_URI = 'http://192.168.12.8:3050/login'

+ 6
- 1
.env.production Zobrazit soubor

@@ -8,4 +8,9 @@ VITE_APP_USE_MOCK = false
VITE_PROXY = [["/api","http://127.0.0.1:8002/api"]]

# base api
VITE_APP_GLOB_BASE_API = '/api'
VITE_APP_GLOB_BASE_API = '/api'

VITE_AUTHORITY = 'http://oidc.dev.t-aaron.com'
VITE_CLIENT_ID = 'tuoheng-pilot-admin'
VITE_CLIENT_SECRET = 'WB0CZ1c6bZLiYP6jLtDFsA=='
VITE_REDIRECT_URI = 'http://192.168.11.11:7011/home'

+ 7
- 2
.env.test Zobrazit soubor

@@ -5,7 +5,12 @@ VITE_PUBLIC_PATH = '/'
VITE_APP_USE_MOCK = false

# proxy
VITE_PROXY = [["","http://192.168.11.11:9055"]]
VITE_PROXY = [["","http://192.168.11.241:9089"]]

# base api
VITE_APP_GLOB_BASE_API = ''
VITE_APP_GLOB_BASE_API = ''

VITE_AUTHORITY = 'http://oidc.test.t-aaron.com'
VITE_CLIENT_ID = 'tuoheng-pilot-admin'
VITE_CLIENT_SECRET = 'WB0CZ1c6bZLiYP6jLtDFsA=='
VITE_REDIRECT_URI = 'http://192.168.11.241:9089/home'

+ 1
- 0
package.json Zobrazit soubor

@@ -18,6 +18,7 @@
"chart-all": "^1.0.2",
"dayjs": "^1.11.2",
"mockjs": "^1.1.0",
"oidc-client": "^1.11.5",
"pinia": "^2.0.13",
"pinia-plugin-persist": "^1.0.0",
"tinymce": "^5.10.2",

+ 1
- 1
src/api/login/index.js Zobrazit soubor

@@ -19,7 +19,7 @@ export function userLogin(data = {}) {
*/
export function getUser() {
return request({
url: '/index/getUserInfo',
url: '/user/getUserInfo',
method: 'get'
})
}

+ 26
- 16
src/layout/components/Header/index.vue Zobrazit soubor

@@ -4,16 +4,17 @@
<n-image height="18" src="/logo.png" preview-disabled />
</div>

<n-dropdown trigger="hover" :options="options" @select="handleSelect">
<n-dropdown v-if="getUserInfo.hasLogin" trigger="hover" :options="options" @select="handleSelect">
<div class="user_msg">
<n-image
<!-- <n-image
class="user_avatar"
:src="userInfo.avatar"
:src="getUserInfo.avatar"
preview-disabled
/>
<span class="user_name">{{ userInfo.realname }}</span>
/> -->
<span class="user_name">{{ getUserInfo.realname }}</span>
</div>
</n-dropdown>
<div v-if="!getUserInfo.hasLogin" class="header__login" @click="handleLogin">登录</div>
</n-layout-header>
</template>

@@ -24,6 +25,7 @@ import { EditOutlined, LogoutOutlined } from '@vicons/antd'
import { renderIcon } from '@/utils'
import { useUserStore } from '@/store/modules/user.js'
import { useSettingStore } from '@/store/modules/setting.js'
import { signinRedirect, signoutRedirect } from '@/utils/oidc/index.js'
export default defineComponent({
name: 'LayoutHeader',
setup() {
@@ -33,11 +35,11 @@ export default defineComponent({
const settingStore = useSettingStore()
const data = reactive({
options: [
{
label: '修改密码',
key: 'edit',
icon: renderIcon(EditOutlined)
},
// {
// label: '修改密码',
// key: 'edit',
// icon: renderIcon(EditOutlined)
// },
{
label: '退出登录',
key: 'out',
@@ -57,21 +59,29 @@ export default defineComponent({
async function handleSelect(key) {
switch (key) {
case 'out':
await logOut()
await signoutRedirect()
}
}

async function logOut() {
const res = await userStore.userLogout()
if (res.code === 0) {
router.replace('/login')
const getUserInfo = computed(() => {
return {
hasLogin: userStore.hasLogin,
// avatar: userStore.avatar,
username: userStore.username,
realname: userStore.realname
}
})

const handleLogin = () => {
signinRedirect()
}

return {
...toRefs(data),
getLogoWidth,
handleSelect
getUserInfo,
handleSelect,
handleLogin
}
}
})

+ 4
- 4
src/layout/index.vue Zobrazit soubor

@@ -37,10 +37,10 @@ const settingStore = useSettingStore()
const menuMode = computed(() => settingStore.getMenuMode)
const tagsMenuSetting = computed(() => settingStore.getTagsMenuSetting)
const useUser = useUserStore()
function getUserNow() {
useUser.getUserInfo()
}
getUserNow()
// function getUserNow() {
// useUser.getUserInfo()
// }
// getUserNow()

</script>


+ 22
- 27
src/router/guard/permission-guard.js Zobrazit soubor

@@ -1,44 +1,39 @@
import { useUserStore } from '@/store/modules/user'
import { usePermissionStore } from '@/store/modules/permission'
import { NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '@/router/routes'
import { getToken } from '@/utils/token'
import { getUserInfo, signinRedirect, signoutRedirect } from '@/utils/oidc/index.js'

const WHITE_LIST = ['/login', '/redirect']
export function createPermissionGuard(router) {
const userStore = useUserStore()
const permissionStore = usePermissionStore()
router.beforeEach(async(to, from, next) => {
// const token = getToken()
const token = true
if (token) {
if (to.path === '/login') {
next({ path: '/' })
const oidcUser = await getUserInfo()
if (oidcUser) {
const hasRoutes = !!permissionStore.permissionRoutes.length
if (hasRoutes) {
next()
} else {
const hasRoutes = !!permissionStore.permissionRoutes.length
if (hasRoutes) {
next()
} else {
try {
// await userStore.getUserInfo()
const routes = await permissionStore.generateRoutesMock(['admin'])
routes.forEach((item) => {
router.addRoute(item)
})
router.addRoute(NOT_FOUND_ROUTE)
router.addRoute(REDIRECT_ROUTE)
next({ ...to, replace: true })
} catch (error) {
// removeToken()
// $message.error(error)
next({ path: '/login', query: { ...to.query, redirect: to.path }})
}
try {
// const { role } = oidcUser.profile
// const roles = role.includes('admin') ? 'admin' : 'flyer'
const userRole = await userStore.getUserInfos() || 1
const roleList = { 1: 'admin', 2: 'flyer' }
const routes = await permissionStore.generateRoutesMock([roleList[userRole]])
routes.forEach((item) => {
router.addRoute(item)
})
router.addRoute(NOT_FOUND_ROUTE)
router.addRoute(REDIRECT_ROUTE)
next({ ...to, replace: true })
} catch (error) {
signinRedirect()
}
}
} else {
if (WHITE_LIST.includes(to.path)) {
if (to.path === '/login') {
next()
} else {
next({ path: '/login', query: { ...to.query, redirect: to.path }})
signinRedirect()
}
}
})

+ 34
- 49
src/store/modules/user.js Zobrazit soubor

@@ -1,71 +1,56 @@
import { defineStore } from 'pinia'
import { userLogin, loginOut } from '@/api/login'
import { getUser } from '@/api/login/index.js'
import { setToken, removeToken } from '@/utils/token'

import { useTagsMenuStore } from './tagsMenu.js'
import { usePermissionStore } from './permission.js'

export const useUserStore = defineStore('user', {
persist: true,
persist: {
enabled: true
},
state() {
return {
userInfo: {}
userInfo: {
hasLogin: false
}
}
},
getters: {
userInfoMsg() {
return this.userInfo
// userId() {
// return this.userInfo?.id
// },
userName() {
return this.userInfo?.userName
},
realname() {
return this.userInfo?.realname
},
avatar() {
return this.userInfo?.avatar
},
role() {
return this.userInfo?.role || []
},
authority() {
return this.userInfo.authority
},
hasLogin() {
return this.userInfo.hasLogin
}
},
actions: {
/* 登录 */
async getLoginToken(form) {
try {
const res = await userLogin(form)
if (res.code === 0) {
/* 设置token */
setToken(res.data.access_token)
this.getUserInfo()
return Promise.resolve(res)
} else {
return Promise.reject(res)
}
} catch (error) {
return Promise.reject(error)
}
},
/* 获取用户信息 */
async getUserInfo() {
const res = await getUser()
if (res.code === 0) {
this.setUserInfo(res.data)
}
},
async userLogout() {
async getUserInfos() {
try {
const res = await loginOut()
const res = await getUser()
if (res.code === 0) {
removeToken()
this.reset()
return Promise.resolve(res)
this.setUserInfo({ hasLogin: true, ...res.data })
return Promise.resolve(res.data.type)
} else {
return Promise.reject(res)
this.setUserInfo()
}
} catch (error) {
return Promise.reject(error)
console.error(error)
this.setUserInfo()
}
},

reset() {
this.$reset()
const tagsMenuStore = useTagsMenuStore()
const permissionStore = usePermissionStore()
tagsMenuStore.$reset()
permissionStore.$reset()
},

setUserInfo(userInfo = {}) {
setUserInfo(userInfo = { hasLogin: false }) {
this.userInfo = { ...this.userInfo, ...userInfo }
}
}

+ 22
- 26
src/utils/http/interceptors.js Zobrazit soubor

@@ -1,6 +1,5 @@
import { router } from '@/router'
import { getToken, removeToken } from '@/utils/token'
import { isWithoutToken } from './help'
import { getUserInfo, signoutRedirect } from '@/utils/oidc/index.js'

export function setupInterceptor(service) {
service.interceptors.request.use(
@@ -12,23 +11,17 @@ export function setupInterceptor(service) {
// 处理不需要token的请求
if (isWithoutToken(config)) {
return config
} else {
const userInfo = await getUserInfo()
if (userInfo) {
const { token_type, access_token } = userInfo
config.headers.Authorization = `${token_type} ${access_token}`
return config
} else {
signoutRedirect()
return Promise.reject({ response: { status: 401, message: '未登录' }})
}
}
// const token = getToken()
const token = 'token'
if (token) {
config.headers.Authorization = token
return config
}
/**
* * 未登录或者token过期的情况下
* * 跳转登录页重新登录,携带当前路由及参数,登录成功会回到原来的页面
*/
const { currentRoute } = router
router.replace({
path: '/login',
query: { ...currentRoute.query, redirect: currentRoute.path }
})
return Promise.reject({ code: '-1', message: '未登录' })
},
(error) => Promise.reject(error)
)
@@ -37,7 +30,6 @@ export function setupInterceptor(service) {
(response) => {
const { method } = response?.config
const { code } = response?.data
const { currentRoute } = router
switch (code) {
case 0:
if (method !== 'get') {
@@ -49,11 +41,7 @@ export function setupInterceptor(service) {
break
case 401:
// 未登录(可能是token过期或者无效了)
removeToken()
router.replace({
path: '/login',
query: { ...currentRoute.query, redirect: currentRoute.path }
})
signoutRedirect()
break
default:
break
@@ -61,7 +49,15 @@ export function setupInterceptor(service) {
return response?.data
},
(error) => {
return Promise.reject(error)
const { status } = error.response
if (status === 401) {
signoutRedirect()
} else if (status === 403) {
$message.error('暂无权限访问,请联系管理员')
return Promise.reject(error)
} else {
return Promise.reject(error)
}
}
)
}
}

+ 91
- 0
src/utils/oidc/index.js Zobrazit soubor

@@ -0,0 +1,91 @@
import { UserManager } from 'oidc-client'
import { createLocalStorage } from '../cache'
let oidcManager = null

export const initServe = () => {
if (oidcManager) return oidcManager
const { VITE_AUTHORITY, VITE_CLIENT_ID, VITE_CLIENT_SECRET, VITE_REDIRECT_URI } = import.meta.env
oidcManager = new UserManager({
/* 认证服务器 */
authority: VITE_AUTHORITY,
/* 客户端id */
client_id: VITE_CLIENT_ID,
client_secret: VITE_CLIENT_SECRET,
/* 回调客户端页面 */
redirect_uri: VITE_REDIRECT_URI,
post_logout_redirect_uri: VITE_REDIRECT_URI,
response_type: 'code',
/* 授权范围 */
scope: 'openid profile',
automaticSilentRenew: true,
revokeAccessTokenOnSignout: true,
metadata: {
issuer: `${VITE_AUTHORITY}`,
authorization_endpoint: `${VITE_AUTHORITY}/oauth2/authorize`,
token_endpoint: `${VITE_AUTHORITY}/oauth2/token`,
userinfo_endpoint: `${VITE_AUTHORITY}/userinfo`,
end_session_endpoint: `${VITE_AUTHORITY}/toLogout`,
revocation_endpoint: `${VITE_AUTHORITY}/oauth2/revoke`
}
})
return oidcManager
}

export const getUserInfo = async() => {
oidcManager = initServe()
return await oidcManager.getUser()
}
/* 登录 */
export const signinRedirect = async() => {
oidcManager = initServe()
oidcManager.signinRedirect({})
.then(res => {
setPath(window.location.pathname)
console.log('signed in', res)
}).catch(err => {
console.err(err)
})
}
/* 登录回调 */
export const signinRedirectCallback = async() => {
const userInfo = await getUserInfo()
if (!userInfo) {
oidcManager = initServe()
return await oidcManager.signinRedirectCallback()
}
}
/* 退出 */
export const signoutRedirect = () => {
oidcManager = initServe()
oidcManager.signoutRedirect({})
.then(function(res) {
setPath(window.location.pathname)
console.log('signed out', res)
}).catch(function(err) {
console.log(err)
})
}
/* 退出回调 */
export const signoutRedirectCallback = async() => {
const userInfo = await getUserInfo()
if (!userInfo) {
oidcManager = initServe()
return await oidcManager.signoutRedirectCallback()
}
}

const PATH_CODE = 'redirect_path'
const DURATION = 24 * 60 * 60
export const isPath = createLocalStorage()
/* 获取Path */
export function getPath() {
return isPath.get(PATH_CODE)
}
/* 设置Path */
export function setPath(Path, duration = DURATION) {
isPath.set(PATH_CODE, Path, duration)
}
/* 移出Path */
export function removePath() {
isPath.remove(PATH_CODE)
}

+ 49
- 3
src/views/login/index.vue Zobrazit soubor

@@ -1,17 +1,63 @@
<template>
<div>
<!-- 1 -->
<div class="login">
<n-spin>
<template #description>
正在进入系统中...
</template>
</n-spin>
</div>
</template>

<script>
import { useRoute, useRouter } from 'vue-router'
import { useUserStore } from '@/store/modules/user'
import { signinRedirectCallback, signoutRedirectCallback, signoutRedirect, getPath, removePath } from '@/utils/oidc/index.js'
export default {
name: 'LoginPage',
setup() {

const route = useRoute()
const router = useRouter()
const userStore = useUserStore()
if (route.query?.code && route.query?.state) {
signinRedirectCallback().then(res => {
// router.push({ path: getPath() })
// removePath()
// userStore.getUserInfos()
const authority = res.profile.authority
const { VITE_PLATFORM } = import.meta.env
if (authority && (authority.includes(VITE_PLATFORM) || authority.includes('admin'))) {
router.push({ path: '/' })
} else {
$message.error('暂无权限访问,请联系管理员')
setTimeout(() => {
signoutRedirect()
}, 2000)
}
}).catch(err => {
console.log(err)
signoutRedirect()
})
// } else if (getPath()) {
// signoutRedirectCallback().then(res => {
// router.push({ path: getPath() })
// userStore.setUserInfo()
// removePath()
// })
}
}
}

</script>
<style scoped lang='scss'>
.login{
width: 100vw;
height: 100vh;
position: relative;
.n-spin-body{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
}
</style>

Načítá se…
Zrušit
Uložit