duancha1065 2017-02-27 14:07
浏览 134

如何在Laravel和Redis中列出所有登录用户?

I'm currently making an app on Laravel (5.3) and require a list of all logged-in users. I was originally going to store them in MySQL but was advised that Redis would be better for the job. Once I looked at Redis docs I was going to store all the users in a set, but then realised you can't set an expire time on individual members, and so opted for namespaced strings instead.

I have written some code that I believe is functioning correctly, but would like advice on improving it/fixing any problems there might be.

So first, here are the two functions I added in LoginController.php

// Overriding the authenticated method from  Illuminate\Foundation\Auth\AuthenticatesUsers
protected function authenticated(Request $request, $user)
{
    $id = $user->id;

    // Getting the expiration from the session config file. Converting to seconds
    $expire = config('session.lifetime') * 60;

    // Setting redis using id as namespace and value
    Redis::SET('users:'.$id,$id);
    Redis::EXPIRE('users:'.$id,$expire);
}

//Overriding the logout method from Illuminate\Foundation\Auth\AuthenticatesUsers
public function logout(Request $request)
{
    // Deleting user from redis database when they log out
    $id = Auth::user()->id;
    Redis::DEL('users:'.$id);

    $this->guard()->logout();

    $request->session()->flush();

    $request->session()->regenerate();

    return redirect('/');
}

Next I wrote Middleware called 'RefreshRedis' in order to refresh the expiration on the Redis when the user does something that refreshes their session.

public function handle($request, Closure $next)
{
    //refreshing the expiration of users key
    if(Auth::check()){
        $id = Auth::user()->id;
        $expire = config('session.lifetime') * 60;
        Redis::EXPIRE('users:'.$id,$expire);
    }
    return $next($request);
}

I then registered the Middleware in $middlewareGroups just after the StartSession Middleware

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \App\Http\Middleware\RefreshRedis::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'bindings',
    ],
];

In order to get a list of all the users I used a modified version of the function found in this thread.

class Team extends AbstractWidget
{

/**
 * Treat this method as a controller action.
 * Return view() or other content to display.
 */
public function run()
{
    //Find all logged users id's from redis
    $users = $this->loggedUsers('users:*');

    return view('widgets.team',compact('users'));
}


protected function loggedUsers($pattern, $cursor=null, $allResults=array())
{
    // Zero means full iteration
    if ($cursor==="0"){
        $users = array ();

        foreach($allResults as $result){
            $users[] = User::where('id',Redis::Get($result))->first();
        }
        return $users;
    }

    // No $cursor means init
    if ($cursor===null){
        $cursor = "0";
    }

    // The call
    $result = Redis::scan($cursor, 'match', $pattern);

    // Append results to array
    $allResults = array_merge($allResults, $result[1]);

    // Get rid of duplicated values
    $allResults = array_unique($allResults);

    // Recursive call until cursor is 0
    return $this->loggedUsers($pattern, $result[0], $allResults);
}
}
  • 写回答

1条回答 默认 最新

  • dongzhang1875 2017-02-27 14:54
    关注

    You can expire Redis set keys by using the [multi] command that would finalize certain Redis command(s) by using the [exec] command.

    protected function authenticated(Request $request, $user)
    {
         $id = $user->id;
    
        // Getting the expiration from the session config file. Converting      to seconds
        $expire = config('session.lifetime') * 60;
    
        // In using the [multi] and [exec] command
        $oLibRedis = $this->callRedisLibrary(); // Initialize your Predis\Client class on this method
        $oLibRedis->multi();
        $oLibRedis->set('users:'.$id, $id);
        $oLibRedis->expire('users:'.$id, $expire);
        $oLibRedis->get('users:'.$id);
        $aResults = $oLibRedis->exec();
        return $aResults
     }
    

    from which it would generate the ff. results

    array(3) { [0]=> object(Predis\Response\Status)#224 (1) { ["payload":"Predis\Response\Status":private]=> string(2) "OK" } [1]=> int(1) [2]=> string(5) "admin" }

    The results will show up as an array based on what commands you have called so far on Redis (e.g set, expire and get commands)

    By the time you wanted to check if the session is expired or not from another controller. You can use the [ttl] command in Redis.

    $sRedisUserKey = $oLibRedis->ttl($sSampleUserKey); // int(7184)
    

    Try to refresh the page to check the countdown for it. Hope this helps for you

    评论

报告相同问题?

悬赏问题

  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 划分vlan后不通了
  • ¥15 GDI处理通道视频时总是带有白色锯齿
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序
  • ¥100 角动量包络面如何用MATLAB绘制
  • ¥15 merge函数占用内存过大
  • ¥15 使用EMD去噪处理RML2016数据集时候的原理
  • ¥15 神经网络预测均方误差很小 但是图像上看着差别太大