优化登录跳转接口
This commit is contained in:
@@ -142,9 +142,14 @@ class Backend extends Api
|
|||||||
|
|
||||||
if ($needLogin) {
|
if ($needLogin) {
|
||||||
if (!$this->auth->isLogin()) {
|
if (!$this->auth->isLogin()) {
|
||||||
|
if ($request->method() === 'GET' && !$this->expectsApiJsonResponse($request)) {
|
||||||
|
$location = $this->adminSpaLoginUrl($request);
|
||||||
|
return redirect($location);
|
||||||
|
}
|
||||||
|
// 必须使用 HTTP 200 返回 JSON:若用 HTTP 303,axios 会跟随重定向,拿不到 JSON,前端无法跳转登录
|
||||||
return $this->error(__('Please login first'), [
|
return $this->error(__('Please login first'), [
|
||||||
'type' => Auth::NEED_LOGIN,
|
'type' => Auth::NEED_LOGIN,
|
||||||
], 0, ['statusCode' => Auth::LOGIN_RESPONSE_CODE]);
|
], 0);
|
||||||
}
|
}
|
||||||
if ($needPermission) {
|
if ($needPermission) {
|
||||||
$controllerPath = $this->getControllerPath($request);
|
$controllerPath = $this->getControllerPath($request);
|
||||||
@@ -167,6 +172,37 @@ class Backend extends Api
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否应按 API 返回 JSON(前端 axios 会带 server: true;纯浏览器地址栏访问多为 HTML Accept)
|
||||||
|
*/
|
||||||
|
protected function expectsApiJsonResponse(WebmanRequest $request): bool
|
||||||
|
{
|
||||||
|
$server = $request->header('server', '');
|
||||||
|
if ($server === 'true' || $server === '1') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (strtolower($request->header('x-requested-with', '')) === 'xmlhttprequest') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
$accept = strtolower($request->header('accept', ''));
|
||||||
|
if (str_contains($accept, 'application/json')) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// 浏览器地址栏/点击链接触发的主文档请求,优先 302 到前端登录(避免误判为 API)
|
||||||
|
if (strtolower((string) $request->header('sec-fetch-mode', '')) === 'navigate') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后台 Vue 为 hash 路由时的登录页(相对路径,与 web/src/router 一致)
|
||||||
|
*/
|
||||||
|
protected function adminSpaLoginUrl(WebmanRequest $request): string
|
||||||
|
{
|
||||||
|
return '/#/admin/login';
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 子类可覆盖,用于初始化 model 等(替代原 initialize)
|
* 子类可覆盖,用于初始化 model 等(替代原 initialize)
|
||||||
* @return Response|null 需直接返回时返回 Response,否则 null
|
* @return Response|null 需直接返回时返回 Response,否则 null
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type { AxiosRequestConfig, Method } from 'axios'
|
import type { AxiosRequestConfig, Method } from 'axios'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { ElLoading, ElNotification, type LoadingOptions } from 'element-plus'
|
import { ElLoading, ElNotification, type LoadingOptions } from 'element-plus'
|
||||||
|
import { nextTick } from 'vue'
|
||||||
import { refreshToken } from '/@/api/common'
|
import { refreshToken } from '/@/api/common'
|
||||||
import { i18n } from '/@/lang/index'
|
import { i18n } from '/@/lang/index'
|
||||||
import router from '/@/router/index'
|
import router from '/@/router/index'
|
||||||
@@ -20,6 +21,12 @@ const loadingInstance: LoadingInstance = {
|
|||||||
count: 0,
|
count: 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 请求是否后台 /admin/ 接口(不依赖当前路由,避免 loading 等场景误判为前台) */
|
||||||
|
function isAdminBackendRequest(config: AxiosRequestConfig): boolean {
|
||||||
|
const u = `${config.baseURL ?? ''}${config.url ?? ''}`
|
||||||
|
return /\/admin\//i.test(u)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据运行环境获取基础请求URL
|
* 根据运行环境获取基础请求URL
|
||||||
*/
|
*/
|
||||||
@@ -112,6 +119,25 @@ function createAxios<Data = any, T = ApiPromise<Data>>(axiosConfig: AxiosRequest
|
|||||||
|
|
||||||
if (response.config.responseType == 'json') {
|
if (response.config.responseType == 'json') {
|
||||||
if (response.data && response.data.code !== 1) {
|
if (response.data && response.data.code !== 1) {
|
||||||
|
const needLogin =
|
||||||
|
response.data.data &&
|
||||||
|
typeof response.data.data === 'object' &&
|
||||||
|
response.data.data.type === 'need login'
|
||||||
|
if (needLogin) {
|
||||||
|
const isAdminAppFlag = isAdminApp() || isAdminBackendRequest(response.config)
|
||||||
|
if (isAdminAppFlag) {
|
||||||
|
adminInfo.removeToken()
|
||||||
|
} else {
|
||||||
|
userInfo.removeToken()
|
||||||
|
}
|
||||||
|
const loginRouteName = isAdminAppFlag ? 'adminLogin' : 'userLogin'
|
||||||
|
if (router.currentRoute.value.name !== loginRouteName) {
|
||||||
|
nextTick(() => {
|
||||||
|
void router.replace({ name: loginRouteName })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return Promise.reject(response.data)
|
||||||
|
}
|
||||||
if (response.data.code == 409) {
|
if (response.data.code == 409) {
|
||||||
if (!window.tokenRefreshing) {
|
if (!window.tokenRefreshing) {
|
||||||
window.tokenRefreshing = true
|
window.tokenRefreshing = true
|
||||||
|
|||||||
Reference in New Issue
Block a user