Consider below scenario.
There are 2 users who registered with the system.
If user 1 is logged in and tries to update User 2's profile. It should not be allowed.
I have tried it using Request class.
use App\Http\Requests\Request;
use Auth;
use App\User;
class ProfileRequest extends Request
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
$routeUser = $this->route('userId');
if($routeUser->id == Auth::user()->id){
return true;
}
else{
abort(403);
}
}
}
Problem: It displays form with all information. It only blocks user when tries to update the info. How to block a user so that he/she cannot even view the form with data??
Use Laravel ACL to manage the role wise user access. By using role wise access only authorized user can access his/her account and do some stuff.
Laravel ACL documentation
Related
I am looking for some clarification as for how exactly to proceed with Oauth auth code PKCE grant when it comes to authorizing my own SPA.
So I get this when I am redirected from my SPA to backend (after I log in of course):
Now I get this, makes sense if I want to login into my app with google or twitter for example.
But If I want to log in to the backend app to get the token with my SPA - is there a way to avoid that every time a user logs in? Does it make sense?
I would like to have it from user perspective like this:
click login
redirect to backend pretending to be SPA (visually)
login
go straight back to SPA without having to confirm that stuff
I just mainly want to understand the process for SPA. I assume and suspect that what I want is simply not possible?
Yes you can :)
Create your own Passport client.
<?php
declare(strict_types=1);
namespace App\Models;
class PassportClient extends \Laravel\Passport\Client
{
/**
* Determine if the client should skip the authorization prompt.
*
* #return bool
*/
public function skipsAuthorization()
{
// todo: add some checks, e.g. $this->name === 'spa-client'
return true;
}
}
And update your App\Providers\AuthServiceProvider.
public function boot()
{
// ...
Passport::useClientModel(PassportClient::class);
}
I need to check in the rules (or authorize) if user can be authorized to delete his comment. ho can i do it? here's my rules
'user_id' => [
'required',
'exists:user,id',
],
I'm checking here if the user exists but how can i checked if user is the same as the logged one?
Right now I'm checking it in controller
public function destroy(CommentDestroyRequest $request, Comment $comment)
{
$userId = Auth::id();
if ($comment->user_id !== $userId)
return response()->json(null, Response::HTTP_FORBIDDEN);
}
but I wanted to move it
The context of the question is not correct. You are trying to use input validation to authorize users.
First; if you want to use logged in user's id to create a new record, you don't need to post it from a form, just use $request->user()->id or Auth::id() as you did. To make sure there is always an authenticated user; add auth middleware for that route (or controller method).
And on the other hand if you want to check if a user authorized to do something you should use authorization services which comes built-in with Laravel.
To accomplish that you can use Gate or Policy
Here is the documentation: https://laravel.com/docs/8.x/authorization
Let's say you want to determine if a user authorized to delete a Comment , you can do this by Writing Gates
You can define gates in your app/Providers/AuthServiceProvider.php file's boot method;
// app/Providers/AuthServiceProvider.php
use App\Models\Comment;
use App\Models\User;
use Illuminate\Support\Facades\Gate;
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('delete-comment', function (User $user, Comment $comment) {
return $user->id === $comment->user_id;
});
}
Now you can use that gate with it's name -which is delete-comment here- to check authorization.
public function destroy(CommentDestroyRequest $request, Comment $comment)
{
if (Gate::denies('delete-comment', $comment)) abort(403);
// Authorization checked, you can do whatever you want
$comment->delete();
return redirect('/comments');
}
Or you can use authorize in a controller;
public function destroy(CommentDestroyRequest $request, Comment $comment)
{
$this->authorize('delete-comment', $comment);
// Authorization checked, you can do whatever you want
$comment->delete();
return redirect('/comments');
}
This will do the trick for you.
But a more convenient way to authorization in Laravel is Policies. You should definitely check and consider to use them.
Policies are classes that organize authorization logic around a
particular model or resource. For example, if your application is a
blog, you may have a App\Models\Post model and a corresponding
App\Policies\PostPolicy to authorize user actions such as creating
or updating posts.
You should save your user_id in comment section too so you can easily detect wether the user is authenticated or not
I am verifying user's account via email and I want to redirect the user directly to home page after account is verified.
The issue I am having is that I am not sure how to actually log in the user using login function.
class VerificationController extends Controller {
public function verify($token){
User::where('email_token',$token)->firstOrFail()->verified();
// auth()->login($user); works if $user exists
return redirect('/home');
}
}
Can I log in the user based on the email_token? I tried but it doesn't seem to work as expected.
You are on the right way. You just need to get the User instance and pass it to the login Method of the Auth class. I've made an example controller for you to show how this could be done.
class VerificationController extends Controller
{
public function verify($token)
{
// Fetch the user by the email token from the database.
// #firstOrFail returns the first matching user or aborts
// the request with a 404 error.
$user = User::where('email_token', $token)->firstOrFail();
// Activate your user or whatever this method does.
$user->verified();
// Logs the Client who did this web request into the
// User account fetched above in.
Auth::login($user);
// Redirect to wherever you want.
return redirect('/home');
}
}
Read more about authenticating users in the official documentation:
https://laravel.com/docs/authentication#other-authentication-methods
First, you have to configure login model in providers section in config/auth.php
Some changes have to made in login model also
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Authenticatable;
class ModelName extends Model implements \Illuminate\Contracts\Auth\Authenticatable
{
use Authenticatable;
}
and in your controller
if (!Auth::attempt(['username' => $username, 'password' => $password])) {
return redirect()->back()->with(['error' => 'Could Not Log You In!']);
} else {
return redirect()->route('routeName');
}
or did you ask to manually authenticate the user from a controller, here is the solution also
Auth::login($user);
where $user is the login model record of corresponding user
I am looking for a way to show a specific view only to specific visitors who get a link to that view. How can I make a middleware so that shows the view only if it comes from a specific source (like if it comes from source.blade.php)
I cannot use the middleware for guest or auth, because then it would give that view to all the auth, but I only want give that view to an auth who has made a payment at beginning and have been redirected from a specific URL.
How can I setup a middleware in such a way that it only shows the view if the auth is being redirected from another view like - source.blade.php
Currently, I have this page setted up like this
public function __construct()
{
$this->middleware('auth:client');
}
This works well, it only shows this page to someone who has logged in from the client authentication guard, but the problem is, any client can visit this page.
I am looking for a way to make it so that it can viewed only by the client who paid at the beginning, and were re-directed by my website. Maybe something like
public function __construct()
{
if(redirect_source="source.blade.php") {$this->middleware('auth:client'); }
}
I think you want a solution that will limit the permission based on your user type.
Middlewares are used to condition certain parameters if you want to let the requester to go into the specific url/route and not to control inside your views.
So if you want to control it, you can use this solution .
namespace App\Laravel\Middleware\Backoffice;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\RedirectResponse;
use Auth, Session;
class ValidSuperUser {
/**
* The Guard implementation.
*
* #var Guard
*/
protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
public function __construct(Guard $auth)
{
$this->auth = $auth;
}
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if($this->auth->user()->type != "super_user") {
Session::flash('notification-status','failed');
Session::flash('notification-title',"Access Denied");
Session::flash('notification-msg','You are not allowed to view the page you are tring to access.');
return redirect()->route('backoffice.dashboard');
}
return $next($request);
}
}
in your Kernel.php under Http folder declare the new Middleware in order to use.
**put it under protected $routeMiddleware = []
and then use it to your routes that need to help that kind of user type.
$route->group(['middleware' => "aliasofyournewmiddle"],function(){
//some routes here
});
your new middleware can be any condition upon the request, so any inputs and available session that has been passed to that url are usable on that middleware, adjust it on how you want to handle the situation.
You can pass a token when redirecting your users to your specific page. Then use your middleware to check whether that token is valid or not.
Say for example, someone made a payment at beginning, you store a hash value of that person's user id or any unique identifier in a session, then redirect the user with the same hash value included in your url. Your middleware can then handle the validation, if the value stored in the session is the same with the value provided in the url.
I have followed the steps of this tutorial in order to setup API authentication in Laravel 5.3 using the auth:api middleware.
Everything is working as expected apart from I am finding that in order to successfully access my API, I only need to provide an API token for any user in my users table rather than the token linked to the user currently logged in.
Is this expected behaviour because this middleware is stateless? I am using AdLdap2 to authenticate users but I can't see what I could be doing wrong especially as I have followed the steps in the tutorial above.
I have also had a look at TokenGuard which deals with API token validation but can't see any logic that ensures the token matches that of the user logged in.
Any help is much appreciated.
I think the authentication works like expected. The only thing auth:api does is making sure you are authenticated to access the protected routes. If you want to protect a specific route to only one user you could use Gates
So if you have a route to access a user like below and you want the user that's logged in to only access herself you can add a gate.
routes/web.php
Route::get('/user/{id}', function ($id) {
$userYourTryingToView = User::find($id);
if (Gate::allows('get-user', $userYourTryingToView)) {
// The user is allowed to access herself, return the user.
return response()->json($userYourTryingToView);
}
// User is not authenticated to view some other user.
return response('Unauthenticated', 403);
});
And in your app/Providers/AuthServiceProvider.php
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
Gate::define('get-user', function ($authenticatedUser, $userYourTryingToView) {
return $authenticatedUser->id == $userYourTryingToView->user_id;
});
}