mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
feat: 未认证设置状态下系统跳转页面功能实现 (#4444)
#### What this PR does / why we need it? #### Summary of your change #### Please indicate you've done the following: - [ ] Made sure tests are passing and test coverage is added if needed. - [ ] Made sure commit message follow the rule of [Conventional Commits specification](https://www.conventionalcommits.org/). - [ ] Considered the docs impact and opened a new docs issue or PR with docs changes if needed.
This commit is contained in:
parent
35785f1e40
commit
3e3f0d9452
@ -121,6 +121,15 @@ func (b *BaseApi) CheckIsSafety(c *gin.Context) {
|
||||
helper.SuccessWithData(c, status)
|
||||
}
|
||||
|
||||
func (b *BaseApi) GetResponsePage(c *gin.Context) {
|
||||
pageCode, err := authService.GetResponsePage()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, pageCode)
|
||||
}
|
||||
|
||||
// @Tags Auth
|
||||
// @Summary Check System isDemo
|
||||
// @Description 判断是否为demo环境
|
||||
|
@ -55,6 +55,7 @@ type SettingInfo struct {
|
||||
|
||||
SnapshotIgnore string `json:"snapshotIgnore"`
|
||||
XpackHideMenu string `json:"xpackHideMenu"`
|
||||
NoAuthSetting string `json:"noAuthSetting"`
|
||||
}
|
||||
|
||||
type SettingUpdate struct {
|
||||
|
@ -20,6 +20,7 @@ type AuthService struct{}
|
||||
|
||||
type IAuthService interface {
|
||||
CheckIsSafety(code string) (string, error)
|
||||
GetResponsePage() (string, error)
|
||||
VerifyCode(code string) (bool, error)
|
||||
Login(c *gin.Context, info dto.Login, entrance string) (*dto.UserLoginInfo, error)
|
||||
LogOut(c *gin.Context) error
|
||||
@ -185,3 +186,11 @@ func (u *AuthService) CheckIsSafety(code string) (string, error) {
|
||||
}
|
||||
return "unpass", nil
|
||||
}
|
||||
|
||||
func (u *AuthService) GetResponsePage() (string, error) {
|
||||
pageCode, err := settingRepo.Get(settingRepo.WithByKey("NoAuthSetting"))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return pageCode.Value, nil
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ func Init() {
|
||||
migrations.AddXpackHideMenu,
|
||||
migrations.AddCronjobCommand,
|
||||
migrations.NewMonitorDB,
|
||||
migrations.AddNoAuthSetting,
|
||||
})
|
||||
if err := m.Migrate(); err != nil {
|
||||
global.LOG.Error(err)
|
||||
|
@ -108,3 +108,13 @@ var NewMonitorDB = &gormigrate.Migration{
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var AddNoAuthSetting = &gormigrate.Migration{
|
||||
ID: "20240328-add-no-auth-setting",
|
||||
Migrate: func(tx *gorm.DB) error {
|
||||
if err := tx.Create(&model.Setting{Key: "NoAuthSetting", Value: "200"}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
@ -18,5 +18,6 @@ func (s *BaseRouter) InitRouter(Router *gin.RouterGroup) {
|
||||
baseRouter.POST("/logout", baseApi.LogOut)
|
||||
baseRouter.GET("/demo", baseApi.CheckIsDemo)
|
||||
baseRouter.GET("/language", baseApi.GetLanguage)
|
||||
baseRouter.GET("/respagecode", baseApi.GetResponsePage)
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,7 @@ export namespace Setting {
|
||||
dingVars: string;
|
||||
snapshotIgnore: string;
|
||||
xpackHideMenu: string;
|
||||
noAuthSetting: string;
|
||||
}
|
||||
export interface SettingUpdate {
|
||||
key: string;
|
||||
|
@ -21,6 +21,10 @@ export const checkIsSafety = (code: string) => {
|
||||
return http.get<string>(`/auth/issafety?code=${code}`);
|
||||
};
|
||||
|
||||
export const getResponsePage = () => {
|
||||
return http.get<string>(`/auth/respagecode`);
|
||||
};
|
||||
|
||||
export const checkIsDemo = () => {
|
||||
return http.get<boolean>('/auth/demo');
|
||||
};
|
||||
|
1
frontend/src/assets/images/error.svg
Normal file
1
frontend/src/assets/images/error.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 21 KiB |
48
frontend/src/components/error-message/error_code.vue
Normal file
48
frontend/src/components/error-message/error_code.vue
Normal file
@ -0,0 +1,48 @@
|
||||
<template>
|
||||
<div class="not-container">
|
||||
<img src="@/assets/images/error.svg" class="not-img" :alt="props.code" />
|
||||
<div class="not-detail">
|
||||
<h2>{{ props.code }}</h2>
|
||||
<h4>{{ $t('setting.' + 'error' + props.code) }}</h4>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const props = defineProps({
|
||||
code: String,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.not-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.not-img {
|
||||
margin-top: 300px;
|
||||
}
|
||||
.not-detail {
|
||||
margin-top: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
h2,
|
||||
h4 {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
h2 {
|
||||
font-size: 60px;
|
||||
color: #434e59;
|
||||
}
|
||||
h4 {
|
||||
margin: 30px 0 20px;
|
||||
font-size: 19px;
|
||||
font-weight: normal;
|
||||
color: #848587;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1388,6 +1388,15 @@ const message = {
|
||||
sslDisable: 'Disable',
|
||||
sslDisableHelper:
|
||||
'If the https service is disabled, you need to restart the panel for it to take effect. Do you want to continue?',
|
||||
noAuthSetting: 'Unauthorized Setting',
|
||||
responseSetting: 'Response Setting',
|
||||
help200: '200 - Help Page',
|
||||
error400: 'Bad Request',
|
||||
error401: 'Unauthorized',
|
||||
error403: 'Forbidden',
|
||||
error404: 'Not Found',
|
||||
error408: 'Request Timeout',
|
||||
error416: 'Range Not Satisfiable',
|
||||
|
||||
https: 'Setting up HTTPS protocol access for the panel can enhance the security of panel access.',
|
||||
certType: 'Certificate type',
|
||||
|
@ -1335,6 +1335,15 @@ const message = {
|
||||
sslChangeHelper: 'https 設置修改需要重啟服務,是否繼續?',
|
||||
sslDisable: '禁用',
|
||||
sslDisableHelper: '禁用 https 服務,需要重啟面板才能生效,是否繼續?',
|
||||
noAuthSetting: '未认证设置',
|
||||
responseSetting: '响应设置',
|
||||
help200: '200 - 幫助頁面',
|
||||
error400: '錯誤請求',
|
||||
error401: '未授權',
|
||||
error403: '禁止訪問',
|
||||
error404: '未找到',
|
||||
error408: '請求超時',
|
||||
error416: '無效請求',
|
||||
|
||||
https: '為面板設置 https 協議訪問,提升面板訪問安全性',
|
||||
certType: '證書類型',
|
||||
|
@ -1336,6 +1336,15 @@ const message = {
|
||||
sslChangeHelper: 'https 设置修改需要重启服务,是否继续?',
|
||||
sslDisable: '禁用',
|
||||
sslDisableHelper: '禁用 https 服务,需要重启面板才能生效,是否继续?',
|
||||
noAuthSetting: '未认证设置',
|
||||
responseSetting: '响应设置',
|
||||
help200: '200 - 帮助页面',
|
||||
error400: '错误请求',
|
||||
error401: '未授权',
|
||||
error403: '禁止访问',
|
||||
error404: '未找到',
|
||||
error408: '请求超时',
|
||||
error416: '无效请求',
|
||||
|
||||
https: '为面板设置 https 协议访问,提升面板访问安全性',
|
||||
certType: '证书类型',
|
||||
|
@ -15,27 +15,29 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!isSafety && !isErr && !isNotFound">
|
||||
|
||||
<div v-if="pageCode === '200' || !pageCode">
|
||||
<UnSafe />
|
||||
</div>
|
||||
|
||||
<div v-if="pageCode !== '200' && pageCode">
|
||||
<ErrCode :code="pageCode" />
|
||||
</div>
|
||||
<div v-if="isErr && mySafetyCode.code === 'err-ip' && !isNotFound">
|
||||
<ErrIP />
|
||||
</div>
|
||||
<div v-if="isErr && mySafetyCode.code === 'err-domain' && !isNotFound">
|
||||
<ErrDomain />
|
||||
</div>
|
||||
<div v-if="isNotFound">
|
||||
<ErrFound />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="login">
|
||||
import { checkIsSafety } from '@/api/modules/auth';
|
||||
import { checkIsSafety, getResponsePage } from '@/api/modules/auth';
|
||||
import LoginForm from '../components/login-form.vue';
|
||||
import UnSafe from '@/components/error-message/unsafe.vue';
|
||||
import ErrIP from '@/components/error-message/err_ip.vue';
|
||||
import ErrFound from '@/components/error-message/404.vue';
|
||||
import ErrCode from '@/components/error-message/error_code.vue';
|
||||
import ErrDomain from '@/components/error-message/err_domain.vue';
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { GlobalStore } from '@/store';
|
||||
@ -46,6 +48,8 @@ const screenWidth = ref(null);
|
||||
const isErr = ref();
|
||||
const isNotFound = ref();
|
||||
|
||||
const pageCode = ref();
|
||||
|
||||
const mySafetyCode = defineProps({
|
||||
code: {
|
||||
type: String,
|
||||
@ -73,6 +77,8 @@ const getStatus = async () => {
|
||||
}
|
||||
isNotFound.value = false;
|
||||
if (res.data !== 'pass') {
|
||||
const resCode = await getResponsePage();
|
||||
pageCode.value = resCode.data;
|
||||
isSafety.value = false;
|
||||
return;
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ const screenWidth = ref(null);
|
||||
const getStatus = async () => {
|
||||
const res = await checkIsSafety(globalStore.entrance);
|
||||
if (res.data === 'unpass') {
|
||||
router.replace({ name: 'entrance' });
|
||||
router.replace({ name: 'entrance', params: { code: 0 } });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -47,6 +47,16 @@
|
||||
<span class="input-help">{{ $t('setting.entranceHelper') }}</span>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('setting.noAuthSetting')">
|
||||
<el-input disabled v-model="form.noAuthSetting">
|
||||
<template #append>
|
||||
<el-button @click="onChangeResponse" icon="Setting">
|
||||
{{ $t('commons.button.set') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item :label="$t('setting.allowIPs')">
|
||||
<div style="width: 100%" v-if="form.allowIPs">
|
||||
<el-input
|
||||
@ -163,6 +173,7 @@
|
||||
<TimeoutSetting ref="timeoutRef" @search="search" />
|
||||
<DomainSetting ref="domainRef" @search="search" />
|
||||
<AllowIPsSetting ref="allowIPsRef" @search="search" />
|
||||
<ResponseSetting ref="responseRef" @search="search()" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -171,6 +182,7 @@ import { ref, reactive, onMounted } from 'vue';
|
||||
import { ElForm, ElMessageBox } from 'element-plus';
|
||||
import PortSetting from '@/views/setting/safe/port/index.vue';
|
||||
import BindSetting from '@/views/setting/safe/bind/index.vue';
|
||||
import ResponseSetting from '@/views/setting/safe/response/index.vue';
|
||||
import SSLSetting from '@/views/setting/safe/ssl/index.vue';
|
||||
import MfaSetting from '@/views/setting/safe/mfa/index.vue';
|
||||
import TimeoutSetting from '@/views/setting/safe/timeout/index.vue';
|
||||
@ -190,6 +202,7 @@ const portRef = ref();
|
||||
const bindRef = ref();
|
||||
const timeoutRef = ref();
|
||||
const mfaRef = ref();
|
||||
const responseRef = ref();
|
||||
|
||||
const sslRef = ref();
|
||||
const sslInfo = ref<Setting.SSLInfo>();
|
||||
@ -210,8 +223,40 @@ const form = reactive({
|
||||
mfaInterval: 30,
|
||||
allowIPs: '',
|
||||
bindDomain: '',
|
||||
noAuthSetting: i18n.global.t('setting.help200'),
|
||||
});
|
||||
|
||||
const noAuthOptions = [
|
||||
{
|
||||
value: '200',
|
||||
label: i18n.global.t('setting.help200'),
|
||||
},
|
||||
{
|
||||
value: '400',
|
||||
label: '400 - ' + i18n.global.t('setting.error400'),
|
||||
},
|
||||
{
|
||||
value: '401',
|
||||
label: '401 - ' + i18n.global.t('setting.error401'),
|
||||
},
|
||||
{
|
||||
value: '403',
|
||||
label: '403 - ' + i18n.global.t('setting.error403'),
|
||||
},
|
||||
{
|
||||
value: '404',
|
||||
label: '404 - ' + i18n.global.t('setting.error404'),
|
||||
},
|
||||
{
|
||||
value: '408',
|
||||
label: '408 - ' + i18n.global.t('setting.error408'),
|
||||
},
|
||||
{
|
||||
value: '416',
|
||||
label: '416 - ' + i18n.global.t('setting.error416'),
|
||||
},
|
||||
];
|
||||
|
||||
const unset = ref(i18n.global.t('setting.unSetting'));
|
||||
|
||||
const search = async () => {
|
||||
@ -232,6 +277,12 @@ const search = async () => {
|
||||
form.mfaInterval = Number(res.data.mfaInterval);
|
||||
form.allowIPs = res.data.allowIPs.replaceAll(',', '\n');
|
||||
form.bindDomain = res.data.bindDomain;
|
||||
|
||||
for (const item of noAuthOptions) {
|
||||
if (item.value === res.data.noAuthSetting) {
|
||||
form.noAuthSetting = item.label;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const onSaveComplexity = async () => {
|
||||
@ -277,6 +328,9 @@ const onChangePort = () => {
|
||||
const onChangeBind = () => {
|
||||
bindRef.value.acceptParams({ ipv6: form.ipv6, bindAddress: form.bindAddress });
|
||||
};
|
||||
const onChangeResponse = () => {
|
||||
responseRef.value.acceptParams({ noAuthSetting: form.noAuthSetting, noAuthOptions: noAuthOptions });
|
||||
};
|
||||
const onChangeBindDomain = () => {
|
||||
domainRef.value.acceptParams({ bindDomain: form.bindDomain });
|
||||
};
|
||||
|
97
frontend/src/views/setting/safe/response/index.vue
Normal file
97
frontend/src/views/setting/safe/response/index.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-drawer v-model="drawerVisible" :destroy-on-close="true" :close-on-click-modal="false" size="30%">
|
||||
<template #header>
|
||||
<DrawerHeader :header="$t('setting.noAuthSetting')" :back="handleClose" />
|
||||
</template>
|
||||
<el-form ref="formRef" label-position="top" :model="form" @submit.prevent v-loading="loading">
|
||||
<el-row type="flex" justify="center">
|
||||
<el-col :span="22">
|
||||
<el-form-item
|
||||
:label="$t('setting.responseSetting')"
|
||||
prop="noAuthSetting"
|
||||
:rules="Rules.requiredSelect"
|
||||
>
|
||||
<el-select v-model="form.noAuthSetting" filterable>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||
<el-button :disabled="loading" type="primary" @click="onSave(formRef)">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref } from 'vue';
|
||||
import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { updateSetting } from '@/api/modules/setting';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import i18n from '@/lang';
|
||||
|
||||
const drawerVisible = ref();
|
||||
const loading = ref();
|
||||
const formRef = ref<FormInstance>();
|
||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
||||
|
||||
const form = reactive({
|
||||
noAuthSetting: '',
|
||||
});
|
||||
|
||||
const options = ref([]);
|
||||
|
||||
interface DialogProps {
|
||||
noAuthSetting: string;
|
||||
noAuthOptions: [{ value: string; label: string }];
|
||||
}
|
||||
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
options.value = params.noAuthOptions;
|
||||
form.noAuthSetting = params.noAuthSetting;
|
||||
drawerVisible.value = true;
|
||||
};
|
||||
|
||||
const onSave = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
loading.value = true;
|
||||
await updateSetting({ key: 'NoAuthSetting', value: form.noAuthSetting })
|
||||
.then(() => {
|
||||
loading.value = false;
|
||||
handleClose();
|
||||
emit('search');
|
||||
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
drawerVisible.value = false;
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss"></style>
|
Loading…
x
Reference in New Issue
Block a user