Localization without route prefix doesn't work - laravel

I'm using the Laravel docs to implement localization (without the prefix in the url).
Basically I want two links "EN" and "NL". Depending on which link I click, the locale should be changed to that specific language.
I use this links:
NL
EN
This route:
Route::get('language/{locale}', 'HomeController#setLang');
And this is my HomeController:
class HomeController extends Controller
{
public function setLang($locale){
App::setLocale($locale);
return back();
}
}
I set my files in resources/lang the way it's explained in the docs.
But, the output ( {{ trans('messages.welcome') }} ) isn't translated.
What am I doing wrong? :)
UPDATE
{{ trans('header.register') }}
Routes
Route::group(['middleware' => ['language']], function () {
//
Route::get('language/{locale}', 'HomeController#setLang');
});
Lang file:
return [
'register' => 'REGISTREER',
];
My Kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'language' => \App\Http\Middleware\Language::class,
];

If you don't want to prefix the urls, you could use the session in conjunction with a middleware.
All you need is a controller and a middleware.
App\Http\Controllers\HomeController method:
class HomeController extends Controller
{
public function setLang($locale)
{
// 1. store selected locale
Session::put('my_project.locale', $locale);
return back();
}
}
App\Http\LocaleMiddleware method:
class LocaleMiddleware
{
public function handle($request, Closure $next)
{
$default = config('app.locale');
// 2. retrieve selected locale if exist (otherwise return the default)
$locale = Session::get('my_project.locale', $default);
// 3. set the locale
App::setLocale($locale);
return $next($request);
}
}
Do not forget to register the middleware globally.

Related

Laravel localization middleware causing ERR_TOO_MANY_REDIRECTS

I am trying to set up localization in a laravel app but my middleware seems to be causing an ERR_TOO_MANY_REDIRECTS error. The site is going to differ per region slightly and I am using the laravel lang/ files to swap out phone numbers etc. This works okay. When I change my locale I get the correct numbers from the lang files. And when I just have the middleware to check if the cookie has been set to set the locale that works too.
I also have middleware to forget the prefix on localised routes so I don't have to update my methods with a locale parameter.
My issue is setting a url prefix if a cookie has been set with an allowed locale in my middleware. I also want to ignore the prefix if the locale is 'en' as it will be default.
Below is the code for everything
routes/web.php
Route::get('/', 'HomeController#index')->name('home');
Route::get('/reader/{identifier}', 'ReaderController#show')->name('reader');
Route::get('/locale/{locale}', SetLocaleController::class)->name('set.locale');
Route::group(['prefix' => '{locale?}', 'where' => ['locale' => implode('|', array_keys(config('app.allowed_locales')))], 'middleware' => 'redirect.localization'], function () {
Route::get('/', 'HomeController#index')->name('home');
Route::middleware('forget.prefix')->get('/reader/{identifier}', 'ReaderController#show')->name('reader');
});
Middleware/Localization.php - This is added to the web middleware group in Kernel.php. It checks for a cookie and sets the locale and should redirect to the proper locale prefix. If no cookie is set then we get the users geo and set it.
public function handle($request, Closure $next)
{
// Get requested url
$segments = collect($request->segments());
if ($segments->count() && Arr::exists(config('app.allowed_locales'), $segments[0])) {
$segments->shift();
}
$locale = Cookie::get('locale');
if ($locale ?? false) {
// Set the app locale.
App::setLocale($locale);
if ($locale != 'en') {
$segments->prepend($locale);
return redirect()->to($segments->implode('/'));
}
} else {
// Check for geo here and set it.
}
return $next($request);
}
Middleware/RedirectLocalization.php - This middleware is only set on the route group for the prefix. It checks if the locale passed is allowed and the sets the locale and cookie. This is set in the $routeMiddleware array in Kernel.php
public function handle($request, Closure $next)
{
$locale = $request->segment(1);
if (Arr::exists(config('app.allowed_locales'), $locale)) {
// Set the app locale.
App::setLocale($locale);
// Save app locale in a Cookie.
Cookie::queue(Cookie::make('locale', $locale, 525600));
}
return $next($request);
}
Controllers/SetLocaleController.php - This is where the locale can be manually set from a menu on the site.
public function __invoke($locale, Request $request)
{
$redirectUrl = parse_url(url()->previous());
$segments = Str::of($redirectUrl['path'])->trim('/')->explode('/');
if (Arr::exists(config('app.allowed_locales'), $segments[0])) {
$segments->shift();
}
if (Arr::exists(config('app.allowed_locales'), $locale)) {
// Set the app locale.
App::setLocale($locale);
// Save app locale in a Cookie.
Cookie::queue(Cookie::make('locale', $locale, 525600));
// Add locale to segments for redirect.
if ($locale != 'en') {
$segments->prepend($locale);
}
} else {
// Set locale to current locale.
App::setLocale(config('app.fallback_locale'));
}
// Redirect back
return redirect()->to($segments->implode('/'));
}
Controllers/ReaderController.php - Nothing out of the ordinary here but I wanted to add it to explain the forget.prefix middleware. If I don't add the forget.prefix middleware then the $reader param becomes the locale.
public function show($reader, Request $request)
{
$reader = Reader::find($reader);
return view('readers.show', [
'reader' => $reader
]);
}
Middleware/ForgetPrefix.php - This middleware removes the prefix so we can access parameter in controller methods without having to add a $locale param to the method in the controller.
public function handle($request, Closure $next)
{
$request->route()->forgetParameter('locale');
return $next($request);
}
So my question is how can I set the URL prefix if the locale has been set in a cookie without getting the too many redirects error?
So I found that my issue was coming from having the Middleware/Localization.php added to the web middleware group. I added this middleware to $routeMiddleware in Kernel.php. Instead I only added the Middleware/Localization.php to the default locale routes.
My updated web/routes.php
Route::group(['middleware' => 'localization'], function () {
Route::get('/', 'HomeController#index')->name('home');
Route::get('/reader/{identifier}', 'ReaderController#show')->name('reader');
});
Route::group(['prefix' => '{locale?}', 'where' => ['locale' => implode('|', array_keys(config('app.allowed_locales')))], 'middleware' => 'redirect.localization'], function () {
Route::get('/', 'HomeController#index')->name('home');
Route::group(['middleware' => 'forget.prefix'], function () {
Route::get('/reader/{identifier}', 'ReaderController#show')->name('reader');
});
});
// Switch Locale route
Route::get('/locale/{locale}', SetLocaleController::class)->name('set.locale');

Laravel - How can I restrict access to admin login page based on IP address in LARAVEL?

How can I restrict access to admin login page based on IP address in LARAVEL?
I want to set a permission to the admin login page to a single IP Address.
you can use Request::ip(); and check it in middleware.. below is basic poc
middleware
class AdminAccessCheck
{
public function handle($request, Closure $next)
{
$ip = $request->ip();
if ($ip === config('admin.ip')) {
return $next($request);
}
return response()->error();
}
}
kernel.php
protected $routeMiddleware = [
...
'admin.ip_check' => \App\Http\Middleware\AdminAccessCheck::class,
];
web.php
Route::middleware(['admin.ip_check'])->group(function() {
//
});
If you prefer package, you can checkout this repo .. Firewall
Create a middleware
php artisan make:middleware IpMiddleware
Code:
<?php
namespace App\Http\Middleware;
use Closure;
class IpMiddleware
{
public function handle($request, Closure $next)
{
if ($request->ip() != "192.168.0.155") {
// here instead of checking a single ip address we can do collection of ips
//address in constant file and check with in_array function
return redirect('home');
}
return $next($request);
}
}
Register the Middleware in app/Http/Kernel.php file
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'ipcheck' => \App\Http\Middleware\IpMiddleware::class,
];
then apply middelware to routes
Route::get('/', ['middleware' => ['ipcheck'], function () {
// your routes here
}]);

Using cookies in laravel to get referral code id?

I have generated a referral code for each user on my platform, and would to use cookies to track if a new user has signed up through someone else(aka. they got referred).
I can generate a url fine, i.e., http://localhost:8888/Test/public/?ref=111222333444
But the cookie doesn't appear to be storing and translating back to my database when I use the code to sign up as a new user
What am I missing?
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Response;
use Closure;
class CheckReferral
{
public function handle($request, Closure $next)
{
if( $request->hasCookie('referral')) {
return $next($request);
}
else {
if( $request->query('ref') ) {
print "yes cookie detected";
return redirect($request->fullUrl())->withCookie(cookie()->forever('referral', $request->query('ref')));
}
}
return $next($request);
}
}
Okay this was my dumb mistake - I overlooked adding the Middleware to my route. Solved it simply by doing this:
use App\Http\Middleware\CheckReferral;
Route::get('/', function () {
return view('welcome');
})->middleware(CheckReferral::class);
Best way to use middleware is to add it in Kernal class by setting it against routeMiddleware array e.g
$routeMiddleware = [
'auth' => \Laravel\Http\Middleware\Authenticate::class,
'guest' => \Laravel\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
...
'check-referral' => \Laravel\Http\Middleware\CheckReferral::class,
];
and then assign the route e.g
Route::get('/', function () {
//
})->middleware('check-referral');
Hope this will help

Laravel login redirected you too many times

I have been struggling with this from quiet a time now, what i am trying is to redirect all the url's hit by non-logged in users to login page and it gives me this error, which I am sure is because it is creating a loop on /login URL. authentication is checking for authorized user in login page also. however I wish the login page should be an exception when checking the auth. I may be doing something wrong which I am not able to get. here goes my code.
routes.php
Route::post('login', 'Auth\AuthController#login');
Route::get('login' , 'Auth\AuthController#showLoginForm');
Route::get('/' , 'Auth\AuthController#showLoginForm');
kernel.php
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'can' => \Illuminate\Foundation\Auth\Access\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'acl' => \App\Http\Middleware\CheckPermission::class,
];
Authenticate class
class Authenticate
{
public function handle($request, Closure $next, $guard = null) {
if (Auth::guard($guard)->guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('login');
}
}
return $next($request);
}
}
AuthController class
class AuthController extends Controller {
use AuthenticatesAndRegistersUsers, ThrottlesLogins;
protected $redirectTo = '/dashboard';
protected $loginPath = '/login';
protected $redirectPath = '/dashboard';
public function __construct(){
$this->middleware('auth', ['except' =>'login']);
/* I have been trying these many things to fix this, all in loss.
// $this->middleware('acl'); // To all methods
// $this->middleware('acl', ['only' => ['create', 'update']]);
// $this->middleware('guest', ['only' => ['/login']]);
// echo "Message"; exit;
// $this->middleware('auth');
// $this->middleware('auth', ['only' => ['login']]);
// $this->middleware('auth', ['only' => ['/login']]);
// $this->middleware('auth', ['except' => 'login']);
// $this->middleware('guest');
// $this->middleware('guest', ['only' => ['logout' , 'login', '/login', '/']]);
}
Please help me, It going all above my head, seems some sort of rocket science to me. well btw I am new to laravel and may be doing some silly thing around, apologies for that. Thanks in Advance.
You need add route login outside Laravel group:
routes.php
Route::auth();
Route::group(['middleware' => 'auth'], function () {
// All route your need authenticated
});
Aditionally, you can see yours route list using:
php artisan route:list
Why you are doing all this just to redirect every non-logged in user to login form?
i think you can just do this
Routes.php
Route::post('login', 'Auth\AuthController#login');
Route::get('login' , 'Auth\AuthController#showLoginForm');
Route::get('/' , 'Auth\AuthController#showLoginForm');
Route::group(['middleware' => 'auth'], function () {
// any route here will only be accessible for logged in users
});
and auth controller construct should be like this
AuthController
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
The problem is with your routes.
When I enter and I am not logged out you send me to login(get) route. And as you are specifying the middleware in the construct function in the AuthController, every time a method of the AuthController is called, construct function is called again and sends you back at login.. and it repeats indefinitely.
like #mkmnstr say
The problem is with your routes.
When I enter and I am not logged out you send me to login(get) route. And as you are specifying the middleware in the construct function in the AuthController, every time a method of the AuthController is called, construct function is called again and sends you back at login.. and it repeats indefinitely.
to fix that u should add
Auth::logout();
Here
...
} else {
Auth::logout(); // user must logout before redirect them
return redirect()->guest('login');
}
...
If your working with custom middleware you must follow it's all rules
in my case, I have to define a custom route class in the web middleware group.
In the world of copy-paste sometime we make mistakes.
Middleware :
public function handle($request, Closure $next)
{
if(!isset(session('user'))){
return redirect('login');
}
return $next($request);
}
}
My Mistake in Kernel.php
if custom middleware class present in web $middlewareGroups will check condition 2 times so it will give error as: redirected you too many times
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\webUser::class, //Remove
],
protected $routeMiddleware = [
'webUser'=> \App\Http\Middleware\webUser::class //Keepit
]
I had same problem after creating my own route service provider. The problem was that when I tried to login, in first time login page showed and after entering credentials I encountered "redirected too many times" and redirected to my admin dashboard and login route!
the solution was: adding middleware "web" into my routes:
Route::middleware('web')->group(base_path('Admin/routes.php'));

How to check if user owns a record with Entrust?

I want to allow users to CRUD only posts they own. I would like not to create a new middleware, but to leverage the existing ones instead. So, Can Entrust's default middlewares be extended to fit this purpose?
class PostsController extends Controller
{
public function __construct()
{
$this->middleware('auth');
$this->middleware('role:blogger|owner'); // <-- implement additional logic in here
}
...
}
#if (Auth::id() === $user->id){
Edit
}
If you have defined in your Kernel.php
protected $routeMiddleware = [
'auth' => '...'
]
In your construct:
public function __construct()
{
$this->middleware('auth', ['only' => ['create']]);
}
using eloquent along with Entrust:
$users = User::whereHas('roles' => function($q){
$q->where('name', 'my-user-role')
})->get();

Resources