我正在尝试将用于用户身份验证的MFA添加到AWS Cognito中用于设备管理的现有解决方案(内置于Angular)中。

我在从用户体验的 Angular 弄清楚如何正确处理此特定响应时遇到了麻烦。实际上,它感觉很碎,如果有人在这里遇到痛点,那会很喜欢。

示例实现请参见Use Case 23.,下面是我的:

authenticate(username: string, password: string): Observable<any> {

    // init cognitoUser here

    return new Observable((observer) => {
        cognitoUser.authenticateUser(authenticationDetails, {
            onSuccess: (result: any) => {},
            onFailure: (err: Error) => {},
            mfaRequired: (codeDeliveryDetails: any) => {

                // SMS has just been sent automatically
                // and it needs to be confirmed within this scope

                // The example linked requests the code via `confirm()`
                // which is awful UX...and since this is a service
                // probably non-compliant with best practice
                // However, without this `confirm` at this point in
                // time, we have no confirmationCode below

                cognitoUser.sendMFACode(confirmationCode, {
                    onSuccess: (result) => {
                        observer.next(result);
                        observer.complete();
                    }, onFailure: (err: Error) => {
                        observer.error(err);
                        observer.complete();
                    }
                });
            }
        });
    });
}

预期的:
  • 如果用户成功通过身份验证,但尚未通过MFA添加此设备,则我们可以管理重定向到适当的确认代码表单页面,并手动触发sendMFACode函数(也许通过某种受限 session 吗?)

  • 问题:
  • 我们没有 session ,因此我们无法询问用户在此登录屏幕之外自动发送的MFA代码...捕获22?
  • 在登录表单中添加另一个显示/隐藏字段无效,因为它将多次击中sendMfaCode函数,从而导致发送了多个SMS代码。

  • 有人有没有走出这种运气的运气?

    最佳答案

    我敢肯定,非常有才华的人在 amazon-cognito-identity-js API上工作,但它设计得很糟糕。这就是为什么它被贬低了。我个人的建议是迁移到放大,这使我不那么生气。

    使用放大,您可以执行这些操作。

    import Amplify from 'aws-amplify'
    import Auth from '@aws-amplify/auth'
    
    let mfaRequired = false
    
    Amplify.configure({
        Auth: {
            userPoolWebClientId: '',
            userPoolId: ''
        }
    })
    
    const logUserIn = (user) => {
      // Go forth and be happy
    }
    
    // Run me on your login form's submit event
    const login = async (username, password) => {
      const user = await Auth.signIn(username, password)
    
      if (user.challengeName === 'SMS_MFA') {
        // Change UI to show MFA Code input
        mfaRequired = true
        return
      }
      return logUserIn(user)
    }
    
    // Run me when the user submits theire MFA code
    const senfMfaCode = async (mfaCode) => {
      const user = await Auth.confirmSignIn(mfaCode)
      return logUserIn(user)
    }
    

    但是,如果出于某种可悲的原因,您需要继续使用 amazon-cognito-identity-js ,请不要担心。我接到你了。

    只需将cognitoUser对象存储在回调外部即可。该文档有点误导人,因为它仅显示了自包含的示例,但没有理由在需要MFA时无法通知UI并随后再调用cognitoUser.sendMFACode()

    请记住,文档显示的是将this传递给sendMFACode()进行范围界定(这很糟糕),但是您可以将回调声明为变量,并在authenticateUser()sendMFACode()函数(或任意数量的函数)之间共享它。
    import { CognitoUserPool, AuthenticationDetails, CognitoUser } from 'amazon-cognito-identity-js'
    
    export let mfaRequired = false
    export let cognitoUser = null
    
    export const cognitoCallbacks = {
      mfaRequired () {
        // Implement you functionality to show UI for MFA form
        mfaRequired = true
      },
      onSuccess (response) {
        // Dance for joy the code gods be glorious.
      },
      onFailure () {
        // Cry.
      }
    }
    
    export const logUserIn = payload => {
      cognitoUser = new CognitoUser({
        Username: 'Matt Damon',
        Pool: new CognitoUserPool({
          UserPoolId: '',
          ClientId: ''
        })
      })
      return cognitoUser.authenticateUser(new AuthenticationDetails(payload), cognitoCallbacks)
    }
    
    export const sendMfaCode = MFACode => {
      cognitoUser.sendMFACode(MFACode, cognitoCallbacks)
    }
    

    这是一个 super 基本的实现,除此之外,
  • 只需覆盖外部模块中的mfaRequired函数即可执行所需的任何操作。
  • 将整个内容包装在pub/sub插件中并订阅事件。

  • 希望对您有所帮助!

    10-08 01:10