I want to use a specific throttle for a website route that sends an email to the user (email validation).
I've used middleware("throttle:3:1"), but the problem is when a user moves in the website, it increases the global throttle, so it looks like it has to wait 1 minute before being able to refresh and get the email.
I've tried to set up a dedicated middleware as proposed by ChatGPT, but not working.
public function handle(Request $request, Closure $next)
{
$throttle = 5; // 5 requests per $ttl (60 seconds)
$ttl = 60; // 60 seconds ttl
$key = sprintf('throttle_CustomValidateEmail:%s:%s', $request->ip(), $request->path());
if (Cache::has($key) && Cache::get($key) >= $throttle) {
return abort(429);
}
Cache::increment($key, 1, $ttl);
return $next($request);
}
In fact, it's working but will never decrease, so if the user refreshes the page too many times, he will definitely be stuck.
How can I handle this problem?
Related
I ask this question while I have done researches to find clear solution for this problem but many of available answers are just how to use Laravel Scheduler itself!
So I am creating a simple website with Laravel to let users create reminders for themselves.Users can receive reminder either on their Emails or if they are logged in, they receive a notification alert something like Facebook Notifications.
I am not sure if I am following the right path or not but I'm using Laravel Scheduler to send reminders to each specific user.
I also use Events in the Laravel to push recent changes every 1 minute to users but my problem is, all users receive same notification. For example if I want to remind an appointment to Mr X, Ms Y also receives same exact notification!!!
At this point, I have two questions:
1 - Is using Laravel Scheduler a good idea for this project or not? If not then what technology or method is recommended?
2 - If I have to use Laravel Scheduler for this project, so how can I send notification to related user? (I cannot use User ID as Laravel Scheduler is running by server itself and not users!)
I also attached my codes to show you what I have up to this point and I know the method I used in Laravel Channels Broadcast is somehow wrong but I just tried it!If anyone knows the answer please help me. Thank you
Laravel Scheduler - Command - Handle Function
public function handle()
{
$reminders = Note::whereTime('task_date', '<=', Carbon::now()->addMinutes(30))
->WhereTime('task_date', '>', Carbon::now()->subMinutes(30))->get();
foreach ($reminders as $reminder) {
if (!$reminder->notified) {
Note::find($reminder->id)
->update(['notified' => 1]);
event(new RemindUsers($reminder));
dd($reminder->title);
}
}
}
Laravel Event
public $reminder;
public function __construct($reminder)
{
$this->reminder = $reminder;
}
public function broadcastOn()
{
return new PrivateChannel('remind.'.$this->reminder->user_id);
}
public function broadcastWith () {
return [
'reminders' => $this->reminder
];
}
Laravel Channels
Broadcast::channel('remind.{id}', function ($user, $id) {
$notes = Note::where('user_id', $id)->get();
foreach ($notes as $note) {
return $user->id === $note->user_id;
}
});
Vue JS Code - Echo Method
data () {
return {
user: 1
}
},
CatchReminders () {
Echo.private(`remind.${this.user}`)
.listen('RemindUsers', (response) => {
this.$toast.info(`${response.reminders.title}`)
})
}
I was wondering if there is any way to update cache TTL from the last time it has accessed?
currently, I have a method to login to adobe connect with API call and API session is valid for 4 days from the last call.
but my cache driver only keeps session in the cache for 4 days from the moment that is added. but I want to keep it for 4 days since the last time it has accessed!
is there any way to update Cache TTL?
I'm sure forgetting and reinserting key is not best practice.
/**
* Login Client Based on information that introduced in environment/config file
*
* #param Client $client
*
* #return void
*/
private function loginClient(Client $client)
{
$config = $this->app["config"]->get("adobeConnect");
$session = Cache::store($config["session-cache"]["driver"])->remember(
$config['session-cache']['key'],
$config['session-cache']['expire'],
function () use ($config, $client) {
$client->login($config["user-name"], $config["password"]);
return $client->getSession();
});
$client->setSession($session);
}
You could listen for the event CacheHit, test for the key pattern, and reset the cache for that key with a new TTL.
To do that, you should create a new listener and add it to the EventServiceProvider:
protected $listen = [
'Illuminate\Cache\Events\CacheHit' => [
'App\Listeners\UpdateAdobeCache',
]
];
And the listener:
class UpdateAdobeCache {
public function handle(CacheHit $event)
{
if ($event->key === 'the_cache_key') { // you could also test for a match with regexp
Cache::store($config["session-cache"]["driver"])->put($event->key, $event->value, $newTTL);
}
}
}
I am working on a project using laravel 4.2. I want when the user is logged in their session will expire in 60 mins and laravel will auto redirect the user without them interacting with web application. however, I am not seeing anything in the laravel docs that explains how to do this approach. If you can assist me with this problem that would be much help thanks.
Well. You should make an AJAX call to the server each minute, and then process the request:
setInterval(function(){
$.get("user/timespan");
}, 6000); // send request each 60 seconds
Now in laravel's controller you put:
class User extends Controller
{
public function timespan() // here we receive AJAX request
{
$allowed_time = 60 * 60; // seconds
$current = time(); // we register current time
$old_time = Session::get("user_loggedin); // we registered this session when user logged in
if( ($current - $old_time) > ($allowed_time) )
{
// do the redirection, since it has stayed more than 60 minutes
}
}
}
The above solution basically works, but you can set Session time limit to 60 minutes in Laravel, and then send the above ajax request and check for the availability of the session. This saves your life from re-computing the 60-minutes duration.
I think the best solution of this is using cookies. When you put session, also add cookie then check the cookie.
When logged;
Sesion::put("user_data",$user_data); // or
Auth:attempt($credentials);
Cookie::queue("session_control","value",60);
And When you want to check cookie (like on filter);
if(!Cookie::has()){
Session::forget('user_data'); //or
Auth::logout();
}
I used my Laravel as a OAuth2 client, and I need to keep token i cookies. So, I set driver to cookie and keep default value for lifetime 120
When any user check remember me on login, I tried to change lifetime with code:
$lifetime = time() + 60 * 60 * 24 * 365;// one year
Config::set('session.lifetime', $lifetime);
But without success. In any another controller I checked value of lifetime and every time I get default value.
\Log::info(\Config::get('session.lifetime'));
Edit #1:
It is enough?
if(Input::has('rememberMe')) {
$lifetime = time() + 60 * 60 * 24 * 365; // one year
Session::put('Expires', $lifetime);
}
Edit #2:
I put acess_token key on the same way as Expires in example above, like:
public function signin() {
/**
* Code for getting *client_code* and *client_state* from API server
*/
$access_token = $this->provider->getAccessToken('authorization_code', $form_data);
// $access_token is object and contain all data (access_token, refresh_token, expires)
Session::put('access_token', $access_token);
Session::put('refresh_token', $access_token->refreshToken);
Session::put('token_expires', $access_token->expires);
if(Input::has('rememberMe')) {
$lifetime = time() + 60 * 60 * 24 * 365; // one year
Session::put('expires', $lifetime);
}
return Response....
}
This is the 'default' Laravel session (I changed driver from file to cookie in /app/config/session.php). I know life time should be set in /app/config/session.php file, but as you can see I need longer life time for Remember me option
Actually when you are setting the value like this in a Controller:
$lifetime = time() + 60 * 60 * 24 * 365;// one year
Config::set('session.lifetime', $lifetime);
It's not updating the value in the file, instead it sets it for the current request only (in memory) and when you check the value using this from another Controller/Request like this:
Config::get('session.lifetime');
You are getting the value from the original value from file system. It's mentioned in the documentation as given below:
Configuration values that are set at run-time are only set for the
current request, and will not be carried over to subsequent requests.
Since it seems to be OK to use cookies as the session driver in your case, you could set the session lifetime to one year in /app/config/session.php by default and store the expiration date of the cookie along with the token in the session. That would allow you to control artificially the validity of the cookie.
Basically, your signin method could look like this:
public function signin() {
/**
* Code for getting *client_code* and *client_state* from API server
*/
$access_token = $this->provider->getAccessToken('authorization_code', $form_data);
// $access_token is object and contain all data (access_token, refresh_token, expires)
Session::put('access_token', $access_token);
Session::put('refresh_token', $access_token->refreshToken);
Session::put('token_expires', $access_token->expires);
if (Input::has('rememberMe')) {
$expires = time() + 60 * 60 * 24 * 365; // one year
} else {
$expires = time() + 60 * 60 * 2; // two hours
}
Session::put('cookie_expires', $expires);
return Response....
}
Then, any time you want to use the access_token, you would check that cookie_expires isn't past first (and if it is, redirect the user to the login page after clearing the session, for example).
I have no idea where the Session::put('expires', $lifetime); will be used. To me, it seems like a normal cookie variable, not actual lifetime associated with any cookie.
You will need to set the cookie lifetime before your cookies are set, and do it the way that Laravel knows you're setting a new cookie lifetime value.
public function signin() {
$access_token = $this->provider->getAccessToken('authorization_code', $form_data);
if (!$access_token) {
return Response... // Respond some other way if authentication failed.
}
// Check rememberMe first so you can set the right session.lifetime before setting any cookies.
if(Input::has('rememberMe')) {
$lifetime = time() + 60 * 60 * 24 * 365; // one year
Config::set('session.lifetime', $lifetime);
}
Session::put('access_token', $access_token);
Session::put('refresh_token', $access_token->refreshToken);
Session::put('token_expires', $access_token->expires);
return Response....
}
I also took the chance to add if (!$access_token) { before setting the cookie since you won't always be authenticating successfully.
Friends Please use the following function instead of numbers
strtotime("+1 year")
It makes more sense for humans
I am using Laravel 3 with two sets of login controllers - the main domain goes to login, all subdomains should route to portal/login#index
I am using the following code in my routes.php:
Route::filter('before', function()
{
$server = explode('.', Request::server('HTTP_HOST'));
if (count($server) == 3)
{
$account = Account::where('subdomain', '=', $server[0])->first();
Session::put('account_id', $account->id);
Route::get('login', 'portal.login#index');
Route::post('login', 'portal.login#index');
Route::get('logout/(:any)', 'portal.login#logout');
}
else
{
// some other stuff - no routing calls in here
}
}
This code works fine for capturing the subdomain & doing the other tasks (such as setting the $account_id), but seem to have no affect on the routing
test.mydomain.com/login should go to portal/login, but instead goes to the main login controller.
I've searched through to be sure there are no filters affecting this (it is an inherited app)
Is this the correct way to set this up, and if so, what else might be affecting this?
TIA!
It's because when you are inside
if (count($server) == 3)
{
// Here
}
The registering of new routes using get/post is not going to respond because the system has already done the route matching, in this case you can forward the request to a new route using
Route::forward($method, $uri);
Which is in laravel/routing/route.php file as given nelow
/**
* Calls the specified route and returns its response.
*
* #param string $method
* #param string $uri
* #return Response
*/
public static function forward($method, $uri)
{
return Router::route(strtoupper($method), $uri)->call();
}
So, if you want to create a request similar to Route::get('login', 'portal.login#index'); then you can do it as
Route::forward('GET', 'login');
In this case, you have keep this route registered just normally you register a route. So, register/add the requests in the routes.php that you want to create dynamically and use Route::forward() method inside
if (count($server) == 3)
{
Route::forward('GET', 'login'); // for a get request
Route::forward('POST', 'login'); // for a post request
}
That's it.