ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Laravel RateLimiter的使用

2021-01-20 02:01:56  阅读:526  来源: 互联网

标签:Laravel function return RateLimiter limiter request maxAttempts key 使用


Laravel RateLimiter的使用

上文说道laravel auth脚手架自带的登陆方法中,存在尝试次数限制,今天来补上

# trait AuthenticatesUsers
public function login(Request $request)
{
    if (method_exists($this, 'hasTooManyLoginAttempts') &&
        $this->hasTooManyLoginAttempts($request)) {
        $this->fireLockoutEvent($request);

        return $this->sendLockoutResponse($request);
    }
    
    if ($this->attemptLogin($request)) {
        return $this->sendLoginResponse($request);
    }
	// 登陆失败就增加次数
    $this->incrementLoginAttempts($request);
	
    return $this->sendFailedLoginResponse($request);
}

# trait ThrottlesLogins
/**
 * Determine if the user has too many failed login attempts.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return bool
 */
protected function hasTooManyLoginAttempts(Request $request)
{
    # $this->limiter()返回laravel默认的RateLimter
    # 以下三个方法可以方便地在LoginController中重写
    # $this->thorrleKey
    # $this->maxAttempts
    # $this->decayMinute
    return $this->limiter()->tooManyAttempts(
        $this->throttleKey($request), $this->maxAttempts()
    );
}

# Illuminate\Cache\RateLimiter
# 注释非常明确 各位自行查看就好 这里只追部分代码
# 可以看到这个类通过缓存存放了key 和 key:timer

# 当我们从容器中解析RateLimter时,还可以选择对应的cache driver
# app(RateLimiter::class, ['cache' => Cache::store('redis')])
# 你也可以使用laravel容器提供的when needs give等api,在服务提供者中自定义你的ratelimiter
# 希望能够带给你些许启发
public function __construct(Cache $cache)
{
    $this->cache = $cache;
}

/**
 * Determine if the given key has been "accessed" too many times.
 *
 * @param  string  $key
 * @param  int  $maxAttempts
 * @return bool
 */
# 我们可以看到这个限制器是根据key指定的 那么就意味着我们可以随意将他用到自己的代码中了啊
# 有点感觉了吗?
public function tooManyAttempts($key, $maxAttempts)
{
    if ($this->attempts($key) >= $maxAttempts) {
        if ($this->cache->has($key.':timer')) {
            return true;
        }

        $this->resetAttempts($key);
    }

    return false;
}

# 如果你真的看了RateLimter的代码,那么应该会猜到登陆失败的话,就会调用limter的hit方法

几种可能会对你有帮助的用法

方式一 保护某个控制器或者方法等

1 创建一个中间件
2 编写中间件,这个中间件你可能希望他长成这样,这里只是简单的例子,你可以根据文档创建功能更强大的中间件
public function __construct(RateLimiter $rateLimiter)
{
    $this->limiter = $rateLimiter
}

public function handle($request, Closure $next)
{
    $accessKey = $request->route()->getActionName();
    // or any key you like

    if ($this->limiter->tooManyAttempts($accessKey, 10)) { 
        return back()->withErrors('kind of hurt, buddy!');
        // you can also throw some custom exceptions, feel free to do express yourself
    }
    $this->limiter->hit($accessKey);

    return $next($request);
}

3 注册该中间件
4 使用中间件
    
# 这里只是将限制器的代码方法放到中间件了,你当然可以将类似的逻辑放到你的代码的任何地方
# 你也可以使用带参数的中间价用来限定某个控制器中的方法的访问频率等等
# 这里的key 尝试次数 窗口时间等 都可以通过中间件参数传递进来
# it's your zone, do whatever you like
    
# 稍微完整些的示例
# 中间件代码
protected $limiter;

public function __construct(RateLImiter $limiter)
{
    $this->limiter = $limiter;
}

public function handle(Request $request, Closure $next, $key, $attempts)
{
    if ($this->limiter->tooManyAttempts($key, $attempts)) { 
        dd('got throttled!');
    }
    $this->limiter->hit($key);

    return $next($request);
}

# 控制器代码
public function __construct(Request $request)
{   
    $action = $request->route()->getActionName();
    $this->middleware("limiter:{$action},2");
}

public function index()
{
    dump('limiter test');
}

# 这样当你第三次访问的时候 默认的就会被禁止访问一分钟了
# 当然也可以将类似的逻辑移动到某个trait或者助手函数中,但这可能会侵入业务代码
# 类似于装饰器的模式 给真正要执行的业务代码再加上一层 各位自行尝试吧

方式二 laravel自带的throttle中间件

# Illuminate\Routing\Middleware\ThrottleRequests
public function handle($request, Closure $next, $maxAttempts = 60, $decayMinutes = 1)
{
    $key = $this->resolveRequestSignature($request);

    $maxAttempts = $this->resolveMaxAttempts($request, $maxAttempts);

    if ($this->limiter->tooManyAttempts($key, $maxAttempts)) {
        throw $this->buildException($key, $maxAttempts);
    }

    $this->limiter->hit($key, $decayMinutes * 60);

    $response = $next($request);

    return $this->addHeaders(
        $response, $maxAttempts,
        $this->calculateRemainingAttempts($key, $maxAttempts)
    );
}

# 相信有了上面的感觉,这段代码看到这就能理解这个中间件是干嘛的了

方式三 laravel8中的RateLimiter有了新的功能,各位可以尝试使用新的方式实现

# 以下代码抄自laravel官方

// Standard rate limit for the entire application users (sanity check...)
RateLimiter::for('global', function (Request $request) {
    return Limit::perMinute(1000);
});

// Limiting based on a custom key segment... such as IP address or anything else you want...
RateLimiter::for('uploads', function (Request $request) {
    Limit::perMinute(10)->by($request->ip()),
});

// Returning no rate limit for certain customers...
RateLimiter::for('podcasts', function (Request $request) {
    if ($request->user()->vipCustomer()) {
        return Limit::none();
    }

    Limit::perMinute(5)->by($request->ip()),
});

// Returning an array of rate limits the request must pass through...
RateLimiter::for('logins', function (Request $request) {
    return [
        Limit::perMinute(100),
        Limit::perMinute(3)->by($request->input('email')),
    ];
});

Route::middleware(['throttle:global'])->group(function () {
    Route::get('/', function () {
        return view('welcome');
    });

    Route::get('/upload', function () {
        return view('welcome');
    })->middleware('throttle:uploads');
});

感谢各位的收看,我们下期再见.

标签:Laravel,function,return,RateLimiter,limiter,request,maxAttempts,key,使用
来源: https://www.cnblogs.com/alwayslinger/p/14300866.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有