if else condition in routes laravel - laravel

I want only user with same name with the url id can access using if condition
Example
User logged on with name jer
He should only access url with /User-Profile/jer
And not access other page /User-Profile/abc that are not equal to his
name
Doing something like Example:
if{id}!=={{auth->name}}
{
Route::get('NoPermission', 'Restriction#index');
}
else
{
Route::get('/User-Profile/{name}/', 'AccountController#index');
}
How can I compare {name} from url to {auth->name} ?
Route
Route::get('/User-Profile/{name}/', 'AccountController#index');
Blade
<a href="/dashboard/User-Profile/{{ Auth::user()->name }}">{{ Auth::user()->name
}}</a>

You can't access Auth like that in your routes, compare it in your AccountController instead:
public function index($name){
if($name != Auth::user->name()) abort(403);
else...
}

In a service provider (Doesn't really matter which one, but it would be clearer if done in the RouteServiceProvider), add a route binding in the boot method as documented in https://laravel.com/docs/6.x/routing#explicit-binding
public function boot()
{
// Declare binding 'name'.
Route::bind('name', function ($name) {
return App\User::where('name', $name)->first() ?? abort(404);
});
}
Then, use that binding in your routes file
// Use binding name and middleware auth to make sure this route can't be accessed by guest users.
Route::get('/User-Profile/{name}/', 'AccountController#index')->middleware('auth')->name('account_profile');
In your blade file, you can do the following
{{-- Make sure the link is only visible for authenticated users https://laravel.com/docs/6.x/blade#if-statements --}}
#auth
<a href="{{ route('account_profile', ['name' => auth()->user()->name]) }}</a>
#endauth

Allow acces to the page , but before showing content ,check if the url path is == to the id name .

Actually, you can check in your routes like this:
Route::get('/profile/{name}', function(String $name) {
if (!Auth::check() || $name !== Auth::user()->name) {
abort(404);
}
return view("view.auth.profile", ['profile => App\Profile::where('user_id', '=', Auth::id())->first()]);
});
However if you use
Route::get('/profile', 'AuthController#profile')->middleware('auth');
and use Auth::user() in your controller to select the correct profile.
The benefit here is that any unauthenticated users will be automatically redirected to your login page, and there's no need to include the name on your profile link.

Related

Laravel 7: How can I restrict URL by user?

I'm a newbie who is learning Laravel 7. I have developed a small web application with Laravel 7. But today I noticed one problem. That all the URLs are global, means all users can access all the URLs of my website. Suppose User A created data and it shows in a table where the edit and delete buttons exist with every row. The edit URL is like: localhost/records/edit/5. The problem is, that other logged-in users can access this edit page also. Like this, all the URLs are accessible by any logged-in users which is very bad.
I hope you understand what I'm saying. I have almost 250+ web routes. Is there any easy way to restrict the routes?
User can access their own data only. How can I do that?
Thanks
You'll have to register policies and ensure users cannot access parts of the website without the correct authorization.
See the docs on how to write policies and implement them.
Sample code:
Policy:
class RecordPolicy
{
public function delete(User $user, Record $record)
{
return $user->id === $record->user_id;
}
}
Controller
class RecordController
{
public function destroy(Record $record)
{
// Authorize the delete action before actually deleting the record
$this->authorize('delete', $record);
$record->delete();
}
}
Records index
#foreach($records as $record)
<div>
{{ $record->name }}
{{-- Only show delete button if the authorized user can actually delete the record --}}
#can('delete', $record)
<form action="{{ route('records.destroy', compact('record') }}" method="POST">
#csrf
#method('DELETE')
<button type="submit">Delete record</button>
</form>
#endcan
</div>
#endforeach
store user_id when new record added > Add created_by field in user_table DB
when user run URL > get logged-in user user_id from session and check in DB for their record > if record not found then redirect to home page with message otherwise continue.
If i understand you correctly you want to restrict routes to specific user.
Create a roles table
Columns (id, name)
(1 = Super Admin, 2 = Admin, 3 = User)
Assign Roles To User While Creating new User
i.e add role_id to users table.
$user = User::create([
'name' => 'First Admin',
'email' => 'admin#admin.com',
'password' => Hash::make('Admin#1234'),
'role_id' => 2 // For admin role
]);
Then Create Middlewares for each role and restrict routes for specific users.
Admin Middleware: AdminMiddleware.php
public function handle(Request $request, Closure $next)
{
$allowedRoles = [2];
if (!in_array(Auth::user()->role_id, $allowedRoles))
{
return redirect()->back()->with('error',__('Sorry, you are not authorized to access that location.'));
}
return $next($request);
}
In Kernel.php
'admin' => \App\Http\Middleware\AdminMiddleware::class,
Route::group(['middleware' => 'admin'], function(){
// All admin Routes
});
You Can also Use Spatie package for this.
https://spatie.be/docs/laravel-permission/v5/basic-usage/middleware
Just Check If Role is allowed to use that route:
Route::group(['middleware' => ['auth', 'role:admin']], function () {
// All routes available for admin
});

Authorization check in Blade Template

I need to control access to the menu items. Here is the Gate Function that is created inside AuthServiceProvider. How do I access it inside a blade template
AuthServiceProvider
Gate::define('isAdmin',function($user){
return $user->type === 'admin';
});
Gate::define('isGeneralUser',function($user){
return $user->type === 'user';
});
Gate::define('isPaidUser',function($user){
return $user->type === 'paid';
});
Gate::define('isSubscriber',function($user){
return $user->type === 'subscriber';
});
Menu
<ul class="dropdown-menu">
<li><a class="hvr-sweep-to-right" href="{{route('weekly-trades')}}">Weekly Trades</a></li>
<li><a class="hvr-sweep-to-right" href="{{route('daily-trade')}}">Daily Trades</a></li>
<li><a class="hvr-sweep-to-right" href="{{route('videos-articles-archive')}}">Videos & Articles Archive</a></li>
<li><a class="hvr-sweep-to-right" href="{{route('blog-list')}}">Surplus forex Blogs</a>
</li>
</ul>
</ul>
You can easily create the if blade directives and show the routes for each role you have, like this:
Blade::if('isRole', function ($role) {
return Auth::check() && Auth::user()->type === $role;
});
Then in your blade template you can filter routes like so:
#isRole('agent')
// Agent routes
#elseisRole('admin')
// Admin routes
#else
// Other routes
#endisRole
P.S: I assumed you want to show routes for the logged in user
EDIT: You actually created Gates which restrict any users to do the given action, it doesn't mean you restricted them access to pages necessarily. You just said that admin users can't do isAdmin action, which doesn't make much sense :)
Update: For checking multiple roles you can change your Blade::if to accept an array of roles instead of a single one:
Blade::if('isRole', function ($roles = []) {
if (empty($roles) || !Auth::check()) {
return false;
}
return in_array(Auth::user()->type, $roles);
});
Then you can use the directive as:
#isRole(['agent', 'admin'])
// User is either agent or admin
#elseisRole(['admin'])
// User is admin
#else
// User is something else
#endisRole
however, it is late but it is useful for someone, here what you want to just admin see write inside the condition
#can('isAdmin')
<!-- The Current User is admin -->
#endcan

Laravel - passing route parameter to blade

I am using Laravel 5.6, with the default make:auth mechanism.
In the routes/web.php, I would like to add a language middleware as follow:-
Route::prefix('{lang}')->group(function () {
Route::get('password/reset', 'Auth\ForgotPasswordController#showLinkRequestForm')->name('password.request');
});
Now I wish to apply this in blade:-
<a href="{{ route('password.request') }}">
But debugger just say:-
Missing required parameters for [Route: password.request] [URI: {lang}/password/reset].
I believe the blade cannot not get the {lang} from route. How can it be achieved?
Try this
<a href="{{ url('en') }}/password/reset">
When you pass a prefix in the route it means that it is going to be included in the route, so when you say
Route::prefix('{lang}')->group(function () {
Route::get('password/reset' .......
Route::get('foo/bar' .......
it means the route will be like this "http://yourwebsite.com/{lang}/password/reset"
"http://yourwebsite.com/{lang}/foo/bar"
so each time you pass any route that falls in that group will need to have a variable called $lang so the link can be initialized.
so in your case
<a href="{{ route('password.request', ['lang' => 'en']) }}"> //you can change en to your preferred language.
if you want to add a middleware to specific route or route group, it is passed in this way
Route::get('/', function () {
//
})->middleware('first', 'second');
or
Route::group(['middleware' => ['first']], function () {
//
});
if you want to create another language, you can check the below links:
Laravel localization
spatie/laravel-translation-loader

Laravel pass exact parameter to route

i have translated url which i need to redirect to the specific controller function, but i need also to pass an exact parameter.
For example i want to show all football news, but in the url i do not have the ID of the sport football (id=1) so i need to pass the parameter id=1 to the index() function.
Route::get('/football-news/', ['as' => 'news.index', 'uses' => 'NewsController#index']);
it is not an option to pass 'football' as a parameter, because it is just an example. The real route is translated and the code looks like that:
Route::get(LaravelLocalization::transRoute('routes.football.news'), ['as' => 'news.index', 'uses' => 'NewsController#index']);
suppose you have a NewsController to fetch all news be like
class NewsController extends Controller
{
public function index()
{
$news = News::all(); //you have to create News model
return view('news.index', compact('news')); //use to pass data in view
}
public function show($id)
{
$news_detail=News::find($id); //to fetch detail of news from database
return view('news.show', compact('news_detail'));
}
}
create index.php and show.php in views/news folder. in index.php
#foreach($news as $news_item)
<div>
{{ $news_item->title }}
</div>
#endforeach
here using "/news/{{$news_item->id}}" you can pass id of specific news into route file.
in show.php
<h1>news</h1>
<h1>
{{ $news_detail->title }}
</h1>
<ul class="list-group">
#foreach($news_detail->detail as $details)
<li class="list-group-item">{{$details}}</li>
#endforeach
</ul>
in route file
Route::get('/news/{news}', 'NewsController#show');
now you have to create show($id) function in NewsController.php which parameter is id.
You can append the index URL with ?id=1 parameter (eg. domain.com?id=1) and get it in your index controller action by using Request::get('id');
For example:
Url in template file:
<a href="domain.com?id=1" />
In your NewsController:
public function index(Request $request){
$id = $request->get('id');
}
You should be able to have access to the parameter even though you didn't specify wildcards in the route file.
Edit:
you will have to call a different #action for a different route. You can pass in an id wildcard.
For example, in Route file:
Route::get('tennis-news/{id}', 'NewsController#tennisIndex');
Route::get('football-news/{id}', 'NewsController#footballIndex');
Then in the NewsControlleryou must have public methods tennisIndex($id) and footballIindex($id), these methods will have access to the wildcard you set in the route.
For example, in NewsController
public function tennisIndex($id){
$tennnis_news = News::where('sport'='tennis)->where('id', $id)->get();
return view('tennis_news', compact('tennnis_news'));
}

Compare route name in blade

I am using Laravel 5.2 and Blade templating, currently I am using this code to send the user to their own profile
href="{{ route('profile.index', ['username' => Auth::user()->username]) }}
This code is in an #if statement in blade, I was wondering how I would be able to check to make sure the user is on their own profile before I show them elements they should only be able to see on their own profile?
Just use check similar to this in your controller:
if (Auth::check()) // Checks if user authenticated
{
$userId = Auth::user()->id; // Gets user ID
// Do some stuff
}
return view('profile', compact('profileInfo'));
In this case any user will see only he's own profile.

Resources