mirror of https://github.com/certd/certd
perf: 群晖支持OTP双重验证登录
parent
df55299e6f
commit
8b8039f42b
|
@ -0,0 +1,33 @@
|
|||
import _ from "lodash-es";
|
||||
import { HttpClient, ILogger } from "../utils";
|
||||
|
||||
export type PluginRequest = {
|
||||
type: "plugin" | "access";
|
||||
typeName: string;
|
||||
action: string;
|
||||
input: any;
|
||||
data: any;
|
||||
};
|
||||
|
||||
export type RequestHandleContext = {
|
||||
http: HttpClient;
|
||||
logger: ILogger;
|
||||
};
|
||||
|
||||
export class RequestHandler {
|
||||
async onRequest(req: PluginRequest, ctx: RequestHandleContext) {
|
||||
if (!req.action) {
|
||||
throw new Error("action is required");
|
||||
}
|
||||
|
||||
const methodName = `on${_.upperFirst(req.action)}`;
|
||||
|
||||
// @ts-ignore
|
||||
const method = this[methodName];
|
||||
if (method) {
|
||||
// @ts-ignore
|
||||
return await this[methodName](req.data, ctx);
|
||||
}
|
||||
throw new Error(`action ${req.action} not found`);
|
||||
}
|
||||
}
|
|
@ -4,3 +4,4 @@ export * from "./context.js";
|
|||
export * from "./storage.js";
|
||||
export * from "./file-store.js";
|
||||
export * from "./license.js";
|
||||
export * from "./handler.js";
|
||||
|
|
|
@ -45,7 +45,7 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
|||
// 创建一个 axios 实例
|
||||
const service = axios.create();
|
||||
|
||||
const defaultAgents = createAgent();
|
||||
// const defaultAgents = createAgent();
|
||||
// 请求拦截
|
||||
service.interceptors.request.use(
|
||||
(config: any) => {
|
||||
|
@ -53,13 +53,14 @@ export function createAxiosService({ logger }: { logger: Logger }) {
|
|||
if (config.timeout == null) {
|
||||
config.timeout = 15000;
|
||||
}
|
||||
let agents = defaultAgents;
|
||||
if (config.skipSslVerify) {
|
||||
agents = createAgent({ rejectUnauthorized: config.rejectUnauthorized });
|
||||
}
|
||||
|
||||
config.httpsAgent = agents.httpsAgent;
|
||||
config.httpAgent = agents.httpAgent;
|
||||
// let agents = defaultAgents;
|
||||
// if (config.skipSslVerify) {
|
||||
// logger.info("跳过SSL验证");
|
||||
// agents = createAgent({ rejectUnauthorized: config.rejectUnauthorized });
|
||||
// }
|
||||
// delete config.skipSslVerify;
|
||||
// config.httpsAgent = agents.httpsAgent;
|
||||
// config.httpAgent = agents.httpAgent;
|
||||
|
||||
return config;
|
||||
},
|
||||
|
|
|
@ -8,6 +8,7 @@ import { CheckCircleOutlined, InfoCircleOutlined, UndoOutlined } from "@ant-desi
|
|||
import CronEditor from "./cron-editor/index.vue";
|
||||
import { CronLight } from "@vue-js-cron/light";
|
||||
import "@vue-js-cron/light/dist/light.css";
|
||||
import Plugins from "./plugins/index";
|
||||
export default {
|
||||
install(app: any) {
|
||||
app.component("PiContainer", PiContainer);
|
||||
|
@ -24,5 +25,6 @@ export default {
|
|||
app.component("UndoOutlined", UndoOutlined);
|
||||
|
||||
app.use(vip);
|
||||
app.use(Plugins);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
import PiSynologyIdDeviceGetter from "./synology/device-id-getter.vue";
|
||||
export default {
|
||||
install(app: any) {
|
||||
app.component("PiSynologyDeviceIdGetter", PiSynologyIdDeviceGetter);
|
||||
}
|
||||
};
|
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<div>
|
||||
<contextHolder />
|
||||
<a-input :value="value" :allow-clear="true" @update:value="emit('update:value', $event)">
|
||||
<template #suffix>
|
||||
<a-tag class="cursor-pointer" @click="getDeviceId">获取设备ID</a-tag>
|
||||
</template>
|
||||
</a-input>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="tsx" setup>
|
||||
import { defineProps, ref, useAttrs } from "vue";
|
||||
import { request } from "/@/api/service";
|
||||
import { Modal } from "ant-design-vue";
|
||||
|
||||
const props = defineProps<{
|
||||
type: string;
|
||||
typeName: string;
|
||||
form: any;
|
||||
value?: any;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
"update:value": any;
|
||||
}>();
|
||||
|
||||
const attrs = useAttrs();
|
||||
|
||||
const otpCodeRef = ref("");
|
||||
|
||||
async function doRequest(action: string, data: any) {
|
||||
const res = await request({
|
||||
url: "/pi/handle",
|
||||
method: "post",
|
||||
data: {
|
||||
type: props.type,
|
||||
typeName: props.typeName,
|
||||
action,
|
||||
data: data,
|
||||
input: props.form.access
|
||||
}
|
||||
});
|
||||
return res;
|
||||
}
|
||||
|
||||
async function loginWithOTPCode(otpCode: string) {
|
||||
return await doRequest("LoginWithOPTCode", {
|
||||
otpCode
|
||||
});
|
||||
}
|
||||
|
||||
const [modal, contextHolder] = Modal.useModal();
|
||||
async function getDeviceId() {
|
||||
//打开对话框
|
||||
|
||||
modal.confirm({
|
||||
title: "请输入OTP验证码",
|
||||
content: () => {
|
||||
return (
|
||||
<a-form-item-rest>
|
||||
<a-input v-model:value={otpCodeRef.value} placeholder="请输入OTP验证码" />
|
||||
</a-form-item-rest>
|
||||
);
|
||||
},
|
||||
onOk: async () => {
|
||||
const res = await loginWithOTPCode(otpCodeRef.value);
|
||||
console.log("did返回", res);
|
||||
emit("update:value", res.did);
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,36 @@
|
|||
import { ALL, Body, Controller, Post, Provide } from '@midwayjs/core';
|
||||
import { Constants } from '../../../basic/constants.js';
|
||||
import { accessRegistry, http, logger, PluginRequest, RequestHandleContext } from '@certd/pipeline';
|
||||
import { merge } from 'lodash-es';
|
||||
import { BaseController } from '../../../basic/base-controller.js';
|
||||
@Provide()
|
||||
@Controller('/api/pi/handle')
|
||||
export class HandleController extends BaseController {
|
||||
@Post('/', { summary: Constants.per.authOnly })
|
||||
async request(@Body(ALL) body: PluginRequest) {
|
||||
const type = body.type;
|
||||
if (type === 'access') {
|
||||
const accessItem = accessRegistry.get(body.typeName);
|
||||
const accessCls = accessItem.target;
|
||||
if (accessCls == null) {
|
||||
throw new Error(`access ${body.typeName} not found`);
|
||||
}
|
||||
//实例化access
|
||||
//@ts-ignore
|
||||
const access = new accessCls();
|
||||
//注入input
|
||||
merge(access, body.input);
|
||||
const ctx: RequestHandleContext = {
|
||||
http: http,
|
||||
logger: logger,
|
||||
};
|
||||
const res = await access.onRequest(body, ctx);
|
||||
|
||||
return this.ok(res);
|
||||
} else if (type === 'plugin') {
|
||||
throw new Error(`plugin:${body.typeName} not support`);
|
||||
} else {
|
||||
throw new Error(`type:${type} not support`);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue