php redis实现用户注册登录

1.注册

需求描述:用户注册时需要提交邮箱、登录密码和昵称。其中邮箱是用户的唯一标识,每个用户的邮箱不能重复,但允许用户修改自己的邮箱。

我们使用散列类型来存储用户的资料,键名为(user:用户ID)。其中用户ID是一个自增的数字,之所以使用 ID 而不是邮箱作为用户的标识是因为考虑到在其他键中可能会通过用户的标识与用户对象相关联,如果使用邮箱作为用户的标识的话在用户修改邮箱时就不得不同时需要修改大量的键名或键值。为了尽可能地减少要修改的地方,我们只把邮箱作为该散列键的一个字段。为此还需要使用一个散列类型的键(email.to.id)来记录邮箱和用户ID间的对应关系以便在登录时能够通过邮箱获得用户的ID。

获取到的参数(通过表单提交也好,通过API接口获取也好不多说了这块)

$email = $_POST['email'];
$password = $_POST['password'];
$nickname = $_POST['nickname'];

下面的代码是判断该邮箱账号是否注册


$redis = new Redis();

if($redis->hexists('email.to.id', $email)) {

     echo '该邮箱已经被注册过了。';

    exit;

}

验证通过后接下来就需要将用户资料存入Redis中。在存储的时候要记住使用散列函数处理用户提交的密码,避免在数据库中存储明文密码。原因是如果数据库中数据泄露(外部原因或内部原因都有可能),攻击者也无法获得用户的真实密码,也便无法正常地登录进系统。更重要的是考虑到用户很可能在其他网站中也使用了同样的密码,所以明文密码泄露还会给用户造成额外的损失。

除此之外,还要避免使用速度较快的散列函数处理密码以防止攻击者使用穷举法破解密码,并且需要为每个用户生成一个随机的“盐”(salt)以避免攻击者使用彩虹表破解。这里作为示例,我们使用Bcrypt算法来对密码进行散列。PHP 5.3中提供的crypt函数支持Bcrypt算法,我们可以实现一个函数来随机生成盐并调用crypt函数获得散列后的密码:

function bcryptHash($rawPassword, $round = 8)

{      

    if ($round < 4 || $round > 31) $round = 8;

    $salt = '$2a$' . str_pad($round, 2, '0', STR_PAD_LEFT) . '$';

    $randomValue = openssl_random_pseudo_bytes(16);

    $salt .= substr(strtr(base64_encode($randomValue), '+', '.'),  0, 22);

    return crypt($rawPassword, $salt);

}

提示 openssl_random_pseudo_bytes函数需要安装OpenSSL扩展。

之后使用如下代码获得散列后的密码:


$hashedPassword = bcryptHash($rawPassword);

存储用户资料就很简单了

$redis = new Redis();

//开启一个事务
$redis->multi();

// 首先获取一个自增的用户ID
$userID = $redis->incr('users:count');

// 存储用户信息
$redis->hmset("user:{$userID}", array(
    'email'  => $email,
    'password'   => $hashedPassword,
    'nickname'   => $nickname
));

// 记得记录下邮箱和用户ID的对应关系
$redis->hset('email.to.id', $email, $userID);

//事务提交
$redis->exec();

echo '注册成功!';

2.登录

需求描述:用户登录时需要提交邮箱和登录密码,如果正确则输出“登录成功”,否则输出“用户名或密码错误”。

当用户提交邮箱和登录密码后首先通过email.to.id键获得用户ID,然后将用户提交的登录密码使用同样的盐进行散列并与数据库存储的密码比对,如果一样则表示登录成功。我们新建一个login.php文件来处理用户的登录,处理该逻辑的部分代码如下:


//获取到的数据
$email = $_POST['email'];
$rawPassword = $_POST['password'];



$redis = new Redis();

// 获得用户的ID
$userID = $redis->hget('email.to.id', $email);

if(!$userID) {
     echo '用户名或密码错误。';
    exit;
}

$hashedPassword = $redis->hget("user:{$userID}", 'password');

现在我们得到了之前存储过的经过散列后的密码,接着定义一个函数来对用户提交的密码进行散列处理。bcryptHash函数中返回的密码中已经包含了盐,所以只需要直接将散列后的密码作为crypt函数的第二个参数,crypt函数会自动地提取出密码中的盐:

function bcryptVerify($rawPassword, $storedHash)

{  

    return crypt($rawPassword, $storedHash) == $storedHash;

}

之后就可以使用此函数进行比对了:

if(!bcryptVerify($rawPassword, $hashedPassword)) {
     echo '用户名或密码错误。';
     exit;
}
echo '登录成功!';
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页