umbraco-mfa-login-provider

安装量: 60
排名: #12425

安装

npx skills add https://github.com/umbraco/umbraco-cms-backoffice-skills --skill umbraco-mfa-login-provider

Umbraco MFA Login Provider What is it? An MFA Login Provider is the UI component for Two-Factor Authentication (2FA) in Umbraco. It provides the interface for users to enable/disable and configure their 2FA provider (e.g., Google Authenticator, SMS codes). The backend ITwoFactorProvider must be configured separately in C# - this extension type handles the frontend setup and configuration UI. Documentation Always fetch the latest docs before implementing: Two-Factor Authentication : https://docs.umbraco.com/umbraco-cms/reference/security/two-factor-authentication Extension Types : https://docs.umbraco.com/umbraco-cms/customizing/extending-overview/extension-types Foundation : https://docs.umbraco.com/umbraco-cms/customizing/foundation Workflow Fetch docs - Use WebFetch on the URLs above Ask questions - What 2FA method? QR code setup? Custom validation UI? Configure backend - Set up C# ITwoFactorProvider first Generate frontend files - Create manifest + configuration element Explain - Show what was created and how to test Minimal Examples Manifest (umbraco-package.json) { "name" : "My MFA Provider" , "extensions" : [ { "type" : "mfaLoginProvider" , "alias" : "My.MfaProvider.Authenticator" , "name" : "Authenticator App MFA" , "forProviderName" : "Umbraco.GoogleAuthenticator" , "element" : "/App_Plugins/MyMfa/mfa-setup.js" , "meta" : { "label" : "Authenticator App" } } ] } Manifest (TypeScript) import type { ManifestMfaLoginProvider } from '@umbraco-cms/backoffice/extension-registry' ; const manifest : ManifestMfaLoginProvider = { type : 'mfaLoginProvider' , alias : 'My.MfaProvider.Authenticator' , name : 'Authenticator MFA Provider' , forProviderName : 'Umbraco.GoogleAuthenticator' , // Must match backend provider name element : ( ) => import ( './mfa-setup.element.js' ) , meta : { label : 'Authenticator App' , } , } ; export const manifests = [ manifest ] ; MFA Setup Element (mfa-setup.element.ts) import { html , css , customElement , property , state } from '@umbraco-cms/backoffice/external/lit' ; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element' ; import { UMB_NOTIFICATION_CONTEXT } from '@umbraco-cms/backoffice/notification' ; import type { UmbMfaProviderConfigurationElementProps } from '@umbraco-cms/backoffice/user' ; @ customElement ( 'my-mfa-setup' ) export class MyMfaSetupElement extends UmbLitElement implements UmbMfaProviderConfigurationElementProps { @ property ( { type : String } ) providerName = '' ; @ property ( { type : String } ) displayName = '' ; @ property ( { attribute : false } ) callback ! : ( providerName : string , code : string , secret : string ) => Promise < { error ? : string }

; @ property ( { attribute : false } ) close ! : ( ) => void ; @ state ( ) private _loading = true ; @ state ( ) private _secret = '' ; @ state ( ) private _qrCodeUrl = '' ; @ state ( ) private _code = '' ; @ state ( ) private _submitting = false ;

notificationContext

? : typeof UMB_NOTIFICATION_CONTEXT . TYPE ; constructor ( ) { super ( ) ; this . consumeContext ( UMB_NOTIFICATION_CONTEXT , ( context ) => { this .

notificationContext

= context ; } ) ; } async connectedCallback ( ) { super . connectedCallback ( ) ; await this .

loadSetupData

( ) ; } async

loadSetupData

( ) { try { // Fetch setup data from API const response = await fetch ( /umbraco/management/api/v1/user/2fa/ ${ this . providerName } /setup ) ; const data = await response . json ( ) ; this . _secret = data . secret ; this . _qrCodeUrl = data . qrCodeSetupImageUrl ; } catch ( error ) { this .

notificationContext

?. peek ( 'danger' , { data : { message : 'Failed to load setup data' } } ) ; } finally { this . _loading = false ; } } async

handleSubmit

( e : SubmitEvent ) { e . preventDefault ( ) ; if ( ! this . _code || this . _code . length !== 6 ) { this .

notificationContext

?. peek ( 'warning' , { data : { message : 'Please enter a 6-digit code' } } ) ; return ; } this . _submitting = true ; try { const result = await this . callback ( this . providerName , this . _code , this . _secret ) ; if ( result . error ) { this .

notificationContext

?. peek ( 'danger' , { data : { message : result . error } } ) ; } else { this .

notificationContext

?. peek ( 'positive' , { data : { message : '2FA enabled successfully' } } ) ; this . close ( ) ; } } finally { this . _submitting = false ; } } render ( ) { if ( this . _loading ) { return html <uui-loader></uui-loader> ; } return html `

Scan this QR code with your authenticator app:

QR Code

Or enter this secret manually: ${ this . _secret }

Verification Code ( this . _code = ( e . target as HTMLInputElement ) . value ) } required >

; } static styles = css

main {

max-width: 400px; margin: 0 auto; text-align: center; } .qr-container { margin: var(--uui-size-space-5) 0; } .qr-container img { max-width: 200px; border: 1px solid var(--uui-color-border); border-radius: var(--uui-border-radius); } code { display: block; margin: var(--uui-size-space-3) 0; padding: var(--uui-size-space-2); background: var(--uui-color-surface-alt); border-radius: var(--uui-border-radius); font-family: monospace; word-break: break-all; } ` ; } export default MyMfaSetupElement ; declare global { interface HTMLElementTagNameMap { 'my-mfa-setup' : MyMfaSetupElement ; } } Using Default MFA Element // If you don't need custom UI, you can use the built-in default element // Just register the manifest without a custom element - Umbraco provides a default const manifest : ManifestMfaLoginProvider = { type : 'mfaLoginProvider' , alias : 'My.MfaProvider.Default' , name : 'Default MFA Provider' , forProviderName : 'Umbraco.GoogleAuthenticator' , // No element specified - uses default meta : { label : 'Authenticator App' , } , } ; Backend C# Configuration (for reference) // ITwoFactorProvider implementation public class GoogleAuthenticatorProvider : ITwoFactorProvider { public string ProviderName => "Umbraco.GoogleAuthenticator" ; public Task < bool

ValidateTwoFactorPIN ( string secret , string code ) { var twoFactorAuthenticator = new TwoFactorAuthenticator ( ) ; return Task . FromResult ( twoFactorAuthenticator . ValidateTwoFactorPIN ( secret , code ) ) ; } public Task < bool

ValidateTwoFactorSetup ( string secret , string code ) { return ValidateTwoFactorPIN ( secret , code ) ; } public async Task < object

GetSetupDataAsync ( Guid userKey , IMemberService memberService ) { var secret = Base32Encoding . ToString ( Guid . NewGuid ( ) . ToByteArray ( ) ) ; var authenticator = new TwoFactorAuthenticator ( ) ; var setupInfo = authenticator . GenerateSetupCode ( "My App" , userKey . ToString ( ) , secret , false ) ; return new { secret , qrCodeSetupImageUrl = setupInfo . QrCodeSetupImageUrl } ; } } // Register in Composer public class MfaComposer : IComposer { public void Compose ( IUmbracoBuilder builder ) { var identityBuilder = new BackOfficeIdentityBuilder ( builder . Services ) ; identityBuilder . AddTwoFactorProvider < GoogleAuthenticatorProvider

( GoogleAuthenticatorProvider . Name ) ; } } Element Props Interface Property Type Description providerName string The provider identifier displayName string Human-readable provider name callback Function Call with code/secret to validate close Function Close the setup modal Callback Function callback ( providerName : string , code : string , secret : string ) : Promise < { error ? : string }

Returns an object with an error property if validation failed, or empty object on success. That's it! Always fetch fresh docs, keep examples minimal, generate complete working code.

返回排行榜