Skip to content

Commit 28d3d04

Browse files
committed
docs: remove already existing docs in next branch
1 parent 41eea76 commit 28d3d04

File tree

1 file changed

+0
-240
lines changed

1 file changed

+0
-240
lines changed

adminforth/documentation/docs/tutorial/07-Plugins/02-TwoFactorsAuth.md

Lines changed: 0 additions & 240 deletions
Original file line numberDiff line numberDiff line change
@@ -206,243 +206,3 @@ plugins: [
206206
],
207207
...
208208
```
209-
210-
## Request 2FA on custom Actions
211-
212-
You might want to to allow to call some custom critical/money related actions with additional 2FA approval. This eliminates risk that user cookies might be stolen by some virous/doorway software after login.
213-
214-
To do it you first need to create custom component which will call `window.adminforthTwoFaModal.getCode(cb?)` frontend API exposed by this plugin. This is awaitable call wich shows 2FA popup and asks user to enter a code.
215-
216-
```ts title='/custom/RequireTwoFaGate.vue'
217-
<template>
218-
<div class="contents" @click.stop.prevent="onClick">
219-
<slot /> <!-- render action defgault contend - button/icon -->
220-
</div>
221-
</template>
222-
223-
<script setup lang="ts">
224-
const emit = defineEmits<{ (e: 'callAction', payload?: any): void }>();
225-
const props = defineProps<{ disabled?: boolean; meta?: Record<string, any> }>();
226-
227-
async function onClick() {
228-
if (props.disabled) return;
229-
230-
const code = await window.adminforthTwoFaModal.getCode(); // this will ask user to enter code
231-
emit('callAction', { code }); // then we pass this code to action (from fronted to backend)
232-
}
233-
</script>
234-
```
235-
236-
Now we need to read code entered on fronted on backend and verify that is is valid and not expired, on backend action handler:
237-
238-
```ts title='/adminuser.ts'
239-
options: {
240-
actions: [
241-
{
242-
name: 'Auto submit',
243-
icon: 'flowbite:play-solid',
244-
allowed: () => true,
245-
action: async ({ recordId, adminUser, adminforth, extra }) => {
246-
//diff-add
247-
const code = extra?.code
248-
//diff-add
249-
if (!code) {
250-
//diff-add
251-
return { ok: false, error: 'No TOTP code provided' };
252-
//diff-add
253-
}
254-
//diff-add
255-
const t2fa = adminforth.getPluginByClassName<TwoFactorsAuthPlugin>('TwoFactorsAuthPlugin');
256-
//diff-add
257-
const result = await t2fa.verify(code, { adminUser });
258-
259-
//diff-add
260-
if (!result?.ok) {
261-
//diff-add
262-
return { ok: false, error: result?.error ?? 'TOTP code is invalid' };
263-
//diff-add
264-
}
265-
//diff-add
266-
await adminforth
267-
//diff-add
268-
.getPluginByClassName<AuditLogPlugin>('AuditLogPlugin')
269-
//diff-add
270-
.logCustomAction({
271-
//diff-add
272-
resourceId: 'aparts',
273-
//diff-add
274-
recordId: null,
275-
//diff-add
276-
actionId: 'visitedDashboard',
277-
//diff-add
278-
oldData: null,
279-
//diff-add
280-
data: { dashboard: 'main' },
281-
//diff-add
282-
user: adminUser,
283-
//diff-add
284-
});
285-
286-
//your critical action logic
287-
288-
return { ok: true, successMessage: 'Auto submitted' };
289-
},
290-
showIn: { showButton: true, showThreeDotsMenu: true, list: true },
291-
//diff-add
292-
customComponent: '@@/RequireTwoFaGate.vue',
293-
},
294-
],
295-
}
296-
```
297-
298-
## Request 2FA from custom components
299-
300-
Imagine you have some button which does some API call
301-
302-
```ts
303-
<template>
304-
<Button @click="callAdminAPI">Call critical API</Button>
305-
</template>
306-
307-
308-
<script setup lang="ts">
309-
import { callApi } from '@/utils';
310-
import adminforth from '@/adminforth';
311-
312-
async function callAdminAPI() {
313-
const code = await window.adminforthTwoFaModal.getCode();
314-
315-
const res = await callApi({
316-
path: '/myCriticalAction',
317-
method: 'POST',
318-
body: { param: 1 },
319-
});
320-
}
321-
</script>
322-
```
323-
324-
On backend you have simple express api
325-
326-
```ts
327-
app.post(`${ADMIN_BASE_URL}/myCriticalAction`,
328-
admin.express.authorize(
329-
async (req: any, res: any) => {
330-
331-
// ... your critical logic ...
332-
333-
return res.json({ ok: true, successMessage: 'Action executed' });
334-
}
335-
)
336-
);
337-
```
338-
339-
You might want to protect this call with a TOTP code. To do it, we need to make this change
340-
341-
```ts
342-
<template>
343-
<Button @click="callAdminAPI">Call critical API</Button>
344-
</template>
345-
346-
347-
<script setup lang="ts">
348-
import { callApi } from '@/utils';
349-
import adminforth from '@/adminforth';
350-
351-
async function callAdminAPI() {
352-
const code = await window.adminforthTwoFaModal.getCode();
353-
354-
// diff-remove
355-
const res = await callApi({
356-
// diff-remove
357-
path: '/myCriticalAction',
358-
// diff-remove
359-
method: 'POST',
360-
// diff-remove
361-
body: { param: 1 },
362-
// diff-remove
363-
});
364-
365-
// diff-add
366-
const res = await callApi({
367-
// diff-add
368-
path: '/myCriticalAction',
369-
// diff-add
370-
method: 'POST',
371-
// diff-add
372-
body: { param: 1, code: String(code) },
373-
// diff-add
374-
});
375-
376-
// diff-add
377-
if (!res?.ok) {
378-
// diff-add
379-
adminforth.alert({ message: res.error, variant: 'danger' });
380-
// diff-add
381-
}
382-
}
383-
</script>
384-
385-
```
386-
387-
And oin API call we need to verify it:
388-
389-
390-
```ts
391-
app.post(`${ADMIN_BASE_URL}/myCriticalAction`,
392-
admin.express.authorize(
393-
async (req: any, res: any) => {
394-
395-
// diff-remove
396-
// ... your critical logic ...
397-
398-
// diff-remove
399-
return res.json({ ok: true, successMessage: 'Action executed' });
400-
401-
// diff-add
402-
const { adminUser } = req;
403-
// diff-add
404-
const { param, code } = req.body ?? {};
405-
// diff-add
406-
const token = String(code ?? '').replace(/\D/g, '');
407-
// diff-add
408-
if (token.length !== 6) {
409-
// diff-add
410-
return res.status(401).json({ ok: false, error: 'TOTP must be 6 digits' });
411-
// diff-add
412-
}
413-
// diff-add
414-
const t2fa = admin.getPluginByClassName<TwoFactorsAuthPlugin>('TwoFactorsAuthPlugin');
415-
// diff-add
416-
const verifyRes = await t2fa.verify(token, { adminUser });
417-
// diff-add
418-
if (!('ok' in verifyRes)) {
419-
// diff-add
420-
return res.status(400).json({ ok: false, error: verifyRes.error || 'Wrong or expired OTP code' });
421-
// diff-add
422-
}
423-
// diff-add
424-
await admin.getPluginByClassName<AuditLogPlugin>('AuditLogPlugin').logCustomAction({
425-
// diff-add
426-
resourceId: 'aparts',
427-
// diff-add
428-
recordId: null,
429-
// diff-add
430-
actionId: 'myCriticalAction',
431-
// diff-add
432-
oldData: null,
433-
// diff-add
434-
data: { param },
435-
// diff-add
436-
user: adminUser,
437-
// diff-add
438-
});
439-
440-
// diff-add
441-
// ... your critical logic ...
442-
443-
// diff-add
444-
return res.json({ ok: true, successMessage: 'Action executed' });
445-
}
446-
)
447-
);
448-
```

0 commit comments

Comments
 (0)