1
0
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:
John Bro 2024-04-09 22:46:09 +08:00 committed by GitHub
parent 35785f1e40
commit 3e3f0d9452
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 276 additions and 7 deletions

View File

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

View File

@ -55,6 +55,7 @@ type SettingInfo struct {
SnapshotIgnore string `json:"snapshotIgnore"`
XpackHideMenu string `json:"xpackHideMenu"`
NoAuthSetting string `json:"noAuthSetting"`
}
type SettingUpdate struct {

View File

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

View File

@ -78,6 +78,7 @@ func Init() {
migrations.AddXpackHideMenu,
migrations.AddCronjobCommand,
migrations.NewMonitorDB,
migrations.AddNoAuthSetting,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View File

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

View File

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

View File

@ -47,6 +47,7 @@ export namespace Setting {
dingVars: string;
snapshotIgnore: string;
xpackHideMenu: string;
noAuthSetting: string;
}
export interface SettingUpdate {
key: string;

View File

@ -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');
};

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

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

View File

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

View File

@ -1335,6 +1335,15 @@ const message = {
sslChangeHelper: 'https 設置修改需要重啟服務是否繼續',
sslDisable: '禁用',
sslDisableHelper: '禁用 https 服務需要重啟面板才能生效是否繼續',
noAuthSetting: '未认证设置',
responseSetting: '响应设置',
help200: '200 - 幫助頁面',
error400: '錯誤請求',
error401: '未授權',
error403: '禁止訪問',
error404: '未找到',
error408: '請求超時',
error416: '無效請求',
https: '為面板設置 https 協議訪問提升面板訪問安全性',
certType: '證書類型',

View File

@ -1336,6 +1336,15 @@ const message = {
sslChangeHelper: 'https 设置修改需要重启服务是否继续',
sslDisable: '禁用',
sslDisableHelper: '禁用 https 服务需要重启面板才能生效是否继续',
noAuthSetting: '未认证设置',
responseSetting: '响应设置',
help200: '200 - 帮助页面',
error400: '错误请求',
error401: '未授权',
error403: '禁止访问',
error404: '未找到',
error408: '请求超时',
error416: '无效请求',
https: '为面板设置 https 协议访问提升面板访问安全性',
certType: '证书类型',

View File

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

View File

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

View File

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

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