Please I need help with Laravel’s policy. I have two guards (Admin and Users with two models of same guards). I’m able to fetch all users posts inside admin’s dashboard. However, I can’t view them since I’m not logged in as a user (show post view is still locked into auth user’s profile for now). Can I possibly use Laravel’s policy from admin’s dashboard to delete a user’s post without logging in as a user? Here is my code so far....
use App\AdminPost;
use App\UserPost;
{
protected $policies = [
AdminPost::class => AdminPostPolicy::class,
UserPost::class => UserPostPolicy::class,
]:
public function boot()
{
$this->registerPolicies();
}
class AdminPolicy
{
public function delete(what goes in here ????)
return $......
}
This is all I can think of so far. I really need help please. Thanks
Related
So I have a booking system. Basically it has this route
localhost:8080/itpr/booking/details/{$bookingId}
Where $bookingId = is the id in the booking_table.
My question, is there a way to hide the $bookingId from my routes from the the user? I don't want other users to be able to access to other booking transaction just by changing the $bookingId in the URL.
The easiest way to achieve this is by submiting your post request via AJAX. But if you are not comfortable using ajax request. You can create a policy that allows only the owner of those booking to make change: see code below.
php artisan make:policy BookingPolicy --model=Booking
Register the policy in your AuthServiceProvider: use App\Policies\BookingPolicy;
protected $policies = [
Booking::class => BookingPolicy::class,
];
Now inside your BookingPolicy then define policy for any method that you want to restrict users from. For example let make sure onl the authenticated user(owner) can update his booking. In this scenario we are assuming that you have user_id column in your Booking table and you have relationship between these 2 tables
public function update(?User $user, Booking $booking)
{
return $user->id === $booking->user_id;
}
Now in your BookingController you can call implement the authorizing actions(can or cant)
public function update(Request $request, $id) {
if ($user->can('update', $booking)) {
// Executes the "create" method on the relevant policy...
}
}
Hopefully this will help :)
have you considered using $table->uuid('id'); for PK? So that the users are not going to guess other bookings easily.
Add a check in your route if the booking ID is one that belongs to the user trying to access the ID. If not, redirect.
Otherwise, provide a dashboard like route showing the user bookings. then make an asynchronous call on the click using your userID/bookingID send that data to a template with a route that is something like your booking/details
Please Check Laravel Policy and define rules to check if the booking id is associated with the current user or not and . which can help you to secure the booking detail from unauthorized user.
I am new to writing policies. I wanna know if I can see data that comes in an policy function.
I have tried googling if it is possible to log something in an policy but I couldn't find anything about this. Now I am just wandering if there is any other possible option to see the data that comes in an policy.
public function show(User $userIdentity, Client $client) {
\Log::info(['log']);
}
I hope someone has an answer for this or another option for me to see the data that is coming through.
Well, yes, if you use the Illuminate\Support\Facades\Log facade you will log stuff. It's nothing related to the policies "per se", if the code gets executed, the log will trigger. If you are looking for architectural suggestions, it depends on the big picture. If that's a simple scenario, that will be enough AND will be fine. If you plan to have complex/multiple logs, you probably want to delegate the logging logic to a dedicated object/package and intercept the event trough an observer, for example.
Docs related to the facede usage here and here
Sure you can, you have to explicitly call your policy, like
$client = Client::find(1);
auth()->user()->can('view', $client);
This is discussed in details here laravel docs
Dont forget to register your policies
use Illuminate\Foundation\Support\Providers\AuthServiceProvider; // auth service provider extends service provider so make sure you take a note of this one
class ReferralServiceProvider extends AuthServiceProvider
{
protected $policies = [
Client::class => ClientPolicy::class
];
public function boot()
{
$this->registerPolicies();
}
}
-
public function show(User $userIdentity, Client $client) {
logger($userIdentity->toJson());
logger($client->toJson());
}
Does laravel provide a way to prevent multiple logins of a user from different devices / browsers at a given time? If yes then how can i force a user to logged in from a single device at a single time. I am developing a online quiz app using laravel 5.6 where users can logged in from a single place and take test.
laravel provide this method to invalidating and "logging out" a user's sessions that are active on other devices logoutOtherDevices()
to work with this method you need also to make sure that the
Illuminate\Session\Middleware\AuthenticateSession
middleware is present and un-commented in your app/Http/Kernel.php class' web middleware group:
'web' => [
// ...
\Illuminate\Session\Middleware\AuthenticateSession::class,
// ...
],
then you can use it like this
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($password);
Perhaps this should get you started:
Add a column in users_table.php
$table->boolean('is_logged_in')->default(false);
When a user logs in: LoginController.php
public function postLogin()
{
// your validation
// authentication check
// if authenticated, update the is_logged_in attribute to true in users table
auth()->user()->update(['is_logged_in' => true]);
// redirect...
}
Now, whenever a user tries to login from another browser or device, it should check if that user is already logged in. So, again in LoginController.php
public function index()
{
if (auth()->check() && auth()->user()->is_logged_in == true) {
// your error logic or redirect
}
return view('path.to.login');
}
When a user logs out: LogoutController.php
public function logout()
{
auth()->user()->update(['is_logged_in' => false]);
auth()->logout();
// redirect to login page...
}
I have a dashboard view that shows certain contain depending on which user is viewing, whether it be an admin or just a regular user.
I can get my admins onto that page, but regular users aren't able to currently because of my middleware guard.
class DashboardController extends Controller {
public function __construct()
{
$this->middleware('auth:admin');
}
public function index()
{
return view('dashboard.index');
}
}
The following code checks on each DashboardController call for auth:admins, but I want regular users to access this too, is there a way to check the auth middleware twice like so?
$this->middleware(['auth:admin','auth']);
So ideally it will check if you're an admin or just a regular auth user.
Also on my view page, when accessing properties of an admin I'm using:
{{ Auth::user()->admin_username }}
Is this normal? I have an admin Model but I'm still accessing it via Auth::user() which feels strange to me, shouldn't it be Auth::admin()->admin_username
Accessing a particular page for users with differing roles is more suited for laravels gates and policy authorization mechanisms.
https://laravel.com/docs/5.5/authorization#writing-gates
These allow you to write fine tuned rules for each use case you have. Simple gates can be defined as closures within your application AuthServiceProvider. For example:
public function boot()
{
$this->registerPolicies();
Gate::define('access-dashboard', function ($user, $post) {
return auth()->check() && (auth()->user()->hasRole('admin') || auth()->user()->hasRole('regular'));
});
}
Then you can use the gate facade wherever necessary, for instance a controller method or constructor.
if (Gate::allows('access-dashboard', $model)) {
// The current user can access dashboard, load their data
}
Alternatively use the can or cant helpers on the user model directly.
if (auth()->user()->can('access-dashboard')) {
//
}
Of course, you can achieve similar via middleware, the advantage of using the above is you can authorize actions at specific points in your code as well as reusability.
As for for last question, as you have it written is correct.
{{ Auth::user()->admin_username }}
Auth::user() or auth()->user() simply returns the currently authenticated user, regardless of their role.
Policies will never work without auth middleware
Assume we´ve got a User and Conversation model with a many-to-many relation.
class User extends Model ... {
public function conversations()
{
return $this->belongsToMany('App\Conversation');
}
}
class Conversation extends Model {
public function users()
{
return $this->belongsToMany('App\User');
}
}
Besides authentication (logging in) which comes out of the box with laravel: How can I protect a specific conversation route for it´s related users?
Which would be the most maintainable way to achieve this? Middleware? Guard? Route model binding? ... right now I´m a bit lost ...
Good question. In this case you'd be best off using Laravel's authorization features. Here are the differences:
Middleware: used to run logic based on either routes or logged in / logged out state. So, if you want to block the conversations entirely from non-logged in users, use a middleware.
Authorization (policies): not to be confused with authentication, is intended for cases where the rules to block someone is not based on route but on some other, more specific reason. These reasons can be anything from roles, to teams, entity ownership, and so on. If you wanted to hide a conversation to only those in the conversation, you can create a policy that kicks the user back to their previous page if they were not in the conversation.
Here's a quick policy you might create:
class ConversationPolicy {
public function view(User $user, Conversation $conv) {
return in_array($user->id, $conv->users->pluck('id'));
}
}
You could check your policy in a controller like the following:
if($request->user()->can('view', $conversation))
{
return view('conversation', ['conversation' => $conversation]);
}
return back()->withError('You are not authorized to view this conversation');
Just be aware you'll have to bind this policy in the AuthServiceProvider before it can be used.