跳到内容

故障排除

编辑此页

如何调试和解决与程序包相关的常见问题。

TOTP / 谷歌验证器代码不被接受

TOTP/谷歌验证器的原理是服务器和您的设备都从共享密钥和当前时间生成相同的身份验证代码。如果这两个组件之一不同步,它们将生成不同的代码。因此

  1. 最常见的问题:确保服务器时间和设备上的时间与实际当前时间同步
  2. 确保设备中使用的密钥与服务器上为帐户配置的密钥匹配
  3. 如果您正在使用 TOTP,请确保应用程序实际上支持您正在使用的特定 TOTP 配置。谷歌验证器应用程序仅支持一种特定的 TOTP 配置(6 位代码,30 秒窗口,sha1 算法)

生成的身份验证代码有一个有效的时间窗口(谷歌验证器中为 30 秒,对于 TOTP,这取决于您的配置)。服务器和设备之间的时间差越大,时间窗口越小,服务器和应用程序生成的代码不匹配的可能性就越高。当时间差大于时间窗口时,就无法提供正确的代码。

为了应对时间差问题,您可以增加 leeway 设置,这样当前时间窗口周围的更多代码将被接受

1
2
3
4
5
6
7
8
9
10
11
# config/packages/scheb_2fa.yaml
scheb_two_factor:

    # For TOTP
    totp:
        leeway: 0  # Acceptable time drift in seconds, must be less or equal than the TOTP period


    # For Google Authenticator
    google:
        leeway: 0  # Acceptable time drift in seconds, must be less or equal than 30 seconds

您可能想要配置一个时间同步服务,例如服务器上的 ntpdate,以确保您的服务器时间始终与 UTC 同步。

谷歌验证器应用程序有一个同步设备时间的选项。打开应用程序并从菜单中选择 Settings > Time correction for codes > Sync now。其他应用程序可能具有类似选项。

注销后重定向回双因素认证表单

问题

当显示双因素认证表单时,您想要取消双因素认证过程。您点击“取消”链接,该链接应执行注销。但它没有执行注销,而是重定向回双因素认证表单。

解决方案

如果您看到这种行为,则安全配置中的 access_control 规则不允许访问注销路径。您的注销路径必须对任何身份验证状态的用户都可访问,这通常通过允许 PUBLIC_ACCESS 来完成。您很可能在安全配置的 access_control 下缺少规则。

配置应类似于此

1
2
3
4
5
# config/packages/security.yaml
security:
    access_control:
        - { path: ^/logout, role: PUBLIC_ACCESS }
        # More rules here ...

确保规则在列表中排在第一位,因为访问控制规则是按顺序评估的。

如果您有这样的规则,但仍然不起作用,则表示出于某种原因,该规则不匹配。绝对确保 path 正则表达式与您的注销路径匹配。如果您有其他选项,例如 hostip,请检查它们是否也匹配。

完成双因素认证后未登录

问题

在您登录并成功通过双因素认证过程后,您未登录。您要么被重定向回登录页面,要么页面显示但缺少已验证的用户。

故障排除

  1. 通过注释掉安全防火墙配置中的所有 two_factor 设置来禁用双因素认证。尝试登录。它是否有效?

    是的,它有效
    继续步骤 2)
    否,它无效

    您的登录过程已损坏。

    解决方案:无法准确判断哪里出了问题。继续调试登录问题。首先解决此问题,然后再重新启用双因素认证。

  2. 恢复步骤 1) 中的更改。通过 var_dump 或任何其他合适的方法,在双因素认证表单页面上调试安全令牌。

    令牌类型应为 TwoFactorToken,并且字段 authenticatedToken 应包含已验证的安全令牌。该已验证的令牌是否将 authenticated=false 设置为?

    您的已验证令牌被标记为无效。请按照以下解决方案操作。
    继续步骤 3)
  3. 完成双因素认证后,当您最终处于未验证状态时,请检查 Symfony 分析器中的最后几个请求。

    对于每个请求,转到 Logs -> Debug。

    它是否显示 Cannot refresh token because user has changedToken was deauthenticated after trying to refresh it

    您的已验证令牌被标记为无效。请按照以下解决方案操作。
    未知问题。尝试通过创建 issue寻求帮助,并告知我们您已测试过的内容。

“您的已验证令牌被标记为无效”的解决方案

最有可能的是,您的用户实体实现了可序列化接口,但并非所有与身份验证过程相关的字段都由序列化/反序列化处理。检查方法 serialize()deserialize() 中使用了哪些字段。

它必须至少是 Symfony\Component\Security\Core\User\UserInterface 中的方法中使用的字段。

如果您的用户实体实现了 Symfony\Component\Security\Core\User\AdvancedUserInterface,您还需要 isAccountNonExpired()isAccountNonLocked()isCredentialsNonExpired()isEnabled() 方法中使用的字段。

登录后未显示双因素认证表单

问题

成功登录后,未显示双因素认证表单。相反,您要么已登录,要么看到应用程序中的其他页面。

基本检查

  • 您的登录页面属于配置了双因素认证的防火墙。
  • 登录页面、登录检查、2fa 和 2fa 检查的路径都位于防火墙的路径 pattern 内。
  • 您的用户实体已实现双因素认证方法所需的接口。
  • 您的用户实体满足至少一种双因素认证方法的要求

    • is*Enabled() 方法返回 true
    • 返回了身份验证方法的其他数据,例如,为了使谷歌验证器工作,getGoogleAuthenticatorSecret() 方法必须返回密钥。

access_control 是否配置正确?

为了使双因素认证表单在双因素认证过程中可访问,您必须为 2fa 路由配置 access_control 规则

配置应类似于此

1
2
3
4
5
6
7
8
# config/packages/security.yaml
security:
    # IMPORTANT: THE ACCESS CONTROL RULE NEEDS TO BE AT THE VERY TOP OF THE LIST!
    access_control:
        # This ensures that the form can only be accessed when two-factor authentication is in progress.
        # The path may be different, depending on how you've configured the route.
        - { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS }
        # Other rules may follow here...

确保规则在列表中排在第一位,因为访问控制规则是按顺序评估的。

如果您已经在列表顶部有这样的规则,请确保 path 正则表达式与您的双因素认证表单路径匹配。如果您有其他选项,例如 hostip,请检查它们是否也匹配。

您的安全设置是否有特殊之处?

问题通常源于应用程序安全设置中的自定义,这通常与角色的授予方式有关。此类问题的示例包括

为了使 2fa 正常工作,必须满足两件事:登录后必须存在 TwoFactorToken,并且在该中间“2fa 未完成”状态下,不得授予任何角色。后者是通过 TwoFactorToken 不在 getRoleNames() 调用中返回任何角色来实现的。但是,如果您以不同于令牌的方式授予角色,则事情将会中断。

此问题的解决方案通常是跳过类型为 TwoFactorTokenInterface 的安全令牌的任何自定义。

1
2
3
4
5
use Scheb\TwoFactorBundle\Security\Authentication\Token\TwoFactorTokenInterface;

if (!($token instanceof TwoFactorTokenInterface)) {
    // Your customization here
}

故障排除

  1. 登录后是否存在 TwoFactorToken

    继续步骤 2)
    继续步骤 3)
  2. 尝试访问需要用户进行身份验证的页面。它是否重定向到双因素认证表单?

    解决方案:您在登录后看到的页面不需要完全验证的用户。最有可能的是,该路径可以通过您的安全 access_control 配置对 PUBLIC_ACCESS 可访问。要么更改您的 access_control 配置,要么在登录后强制重定向用户到需要完全身份验证的页面。
    未知问题。尝试通过创建 issue寻求帮助,并告知我们您已测试过的内容。
  3. 在登录时,您是否到达方法 Scheb\TwoFactorBundle\Security\Authentication\Provider\AuthenticationProviderDecorator::authenticate() 的末尾(return 语句)?

    继续步骤 4)
    程序包的集成存在问题。尝试通过创建 issue`_ 寻求帮助,并告知我们您已测试过的内容。
  4. 在登录时,是否调用了方法 Scheb\TwoFactorBundle\Security\TwoFactor\Handler\TwoFactorProviderInitiator::getActiveTwoFactorProviders()

    是的,已调用
    继续步骤 5)
    否,未调用
    解决方案:双因素认证被跳过,要么是因为 IP 白名单,要么是因为受信任设备令牌。IP 白名单是程序包配置的一部分。您可能已将“localhost”或“127.0.0.1”列入白名单?可以使用浏览器的开发者工具删除受信任设备 Cookie。
  5. Scheb\TwoFactorBundle\Security\TwoFactor\Handler\TwoFactorProviderInitiator::getActiveTwoFactorProviders() 是否返回任何值?

    是的,它返回一个字符串数组
    未知问题。尝试通过创建 issue寻求帮助,并告知我们您已测试过的内容。
    否,它返回一个空数组
    解决方案:您的用户没有活动的双因素认证方法。is*Enabled 方法返回 false,或者缺少必要的数据(例如,谷歌验证器密钥)。

问题

在您完成 2fa 后,您期望该设备被标记为“受信任设备”,但未设置受信任设备 Cookie。

基本检查

  • 2fa 已通过该调用完成,并且您之后已完全验证。
  • 与 2fa 代码一起,您发送了带有类似 true 值的受信任参数(默认 _trusted)。(背景信息:设备不会自动标记为受信任。用户必须选择是否可以信任该设备。这就是为什么必须发送此额外参数的原因。)

故障排除

查看您发送 2fa 和受信任参数时 HTTP 调用的响应。您是否看到设置了 Cookie(Set-Cookie 标头)?

请验证 Cookie 的参数。确保该 Cookie 的一切正常:路径、域名和其他 Cookie 选项。您是否尝试为顶级域名设置它
否,未设置 Cookie
未知问题。尝试通过创建 issue寻求帮助,并告知我们您已测试过的内容。
包括代码示例在内的本作品根据 Creative Commons BY-SA 3.0 许可协议获得许可。
目录
    版本