簡體   English   中英

如何在 PHP 中使用 Google Authenticator 生成唯一的二維碼?

[英]How to generate unique QR codes with Google Authenticator in PHP?

希望我們 PHP 系統上的每個用戶都有一個唯一的二維碼。 我已經實現了 Google Authenticator 系統,但它只為每個用戶生成相同的二維碼,一個用戶可以使用他們的代碼登錄另一個用戶的帳戶。

如何讓 Google Authenticator 為每個用戶生成唯一代碼? 我需要將什么值/變量傳遞給 Google 身份驗證器才能為我們系統上的每個用戶帳戶提供唯一代碼?

我們嘗試傳遞用戶的電子郵件地址或用戶名,但盡管電子郵件地址是唯一的,但身份驗證器還是發回了相同的二維碼。

[1]使用 username , username 變量名是 $name

public function getQR($name, $secret, $title = null, $params = array())
    {
        $width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
        $height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
        $level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';


        $urlencoded = urlencode('otpauth://totp/'.$name.'?secret='.$secret.'');
        if (isset($title)) {
            $urlencoded .= urlencode('&issuer='.urlencode($title));
        }

        return 'https://chart.googleapis.com/chart?chs='.$width.'x'.$height.'&chld='.$level.'|0&cht=qr&chl='.$urlencoded.'';
    }

    public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
    {
        if ($currentTimeSlice === null) {
            $currentTimeSlice = floor(time() / 30);
        }

        if (strlen($code) != 6) {
            return false;
        }

        for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
            $calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
            if ($this->timingSafeEquals($calculatedCode, $code)) {
                return true;
            }
        }

        return false;
    }

[2]使用 email ,email 變量名是 $email

public function getQR($email, $secret, $title = null, $params = array())
    {
        $width = !empty($params['width']) && (int) $params['width'] > 0 ? (int) $params['width'] : 200;
        $height = !empty($params['height']) && (int) $params['height'] > 0 ? (int) $params['height'] : 200;
        $level = !empty($params['level']) && array_search($params['level'], array('L', 'M', 'Q', 'H')) !== false ? $params['level'] : 'M';


        $urlencoded = urlencode('otpauth://totp/'.$email.'?secret='.$secret.'');
        if (isset($title)) {
            $urlencoded .= urlencode('&issuer='.urlencode($title));
        }

        return 'https://chart.googleapis.com/chart?chs='.$width.'x'.$height.'&chld='.$level.'|0&cht=qr&chl='.$urlencoded.'';
    }

    public function verifyCode($secret, $code, $discrepancy = 1, $currentTimeSlice = null)
    {
        if ($currentTimeSlice === null) {
            $currentTimeSlice = floor(time() / 30);
        }

        if (strlen($code) != 6) {
            return false;
        }

        for ($i = -$discrepancy; $i <= $discrepancy; ++$i) {
            $calculatedCode = $this->getCode($secret, $currentTimeSlice + $i);
            if ($this->timingSafeEquals($calculatedCode, $code)) {
                return true;
            }
        }

        return false;
    }

我希望代碼為每個用戶生成一個唯一的二維碼,以便每個用戶在手機上的 Google 身份驗證器應用程序中都有自己的身份驗證代碼。

秘密只不過是一個隨機的 base32 字符串。 所以可以像這樣簡單地完成

 substr( str_shuffle( "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567" ), 0, 32 );

其中“ABCDEFGHIJKLMNOPQRSTUVWXYZ234567”是base32字母表

您的代碼看起來與https://github.com/PHPGangsta/GoogleAuthenticator非常相似,導致不同用戶使用類似 QR 碼的問題是您為他們使用相同的秘密。

每個用戶都必須擁有獨一無二的秘密!

PHPGangsta 有一個生成偽隨機秘密的函數:

public function createSecret($secretLength = 16)
{
    $validChars = $this->_getBase32LookupTable();

    // Valid secret lengths are 80 to 640 bits
    if ($secretLength < 16 || $secretLength > 128) {
        throw new Exception('Bad secret length');
    }
    $secret = '';
    $rnd = false;
    if (function_exists('random_bytes')) {
        $rnd = random_bytes($secretLength);
    } elseif (function_exists('mcrypt_create_iv')) {
        $rnd = mcrypt_create_iv($secretLength, MCRYPT_DEV_URANDOM);
    } elseif (function_exists('openssl_random_pseudo_bytes')) {
        $rnd = openssl_random_pseudo_bytes($secretLength, $cryptoStrong);
        if (!$cryptoStrong) {
            $rnd = false;
        }
    }
    if ($rnd !== false) {
        for ($i = 0; $i < $secretLength; ++$i) {
            $secret .= $validChars[ord($rnd[$i]) & 31];
        }
    } else {
        throw new Exception('No source of secure random');
    }

    return $secret;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM