I am trying to use laravel policies to check if a story is "visible" and if it isn't, if the authenticated user ownes the story (in which case he can still view it). I set up my policy using
php artisan make:policy StoryPolicy --model=Story
There I set up the checks required to see if the authenticated user can see the Story or not
<?php
namespace App\Policies;
use App\User;
use App\Story;
use Illuminate\Auth\Access\HandlesAuthorization;
class StoryPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view the story.
*
* #param \App\User $user
* #param \App\Story $story
* #return mixed
*/
public function view(User $user, Story $story)
{
if ($story->visibility == 'visible') {
return true;
} else {
return $story->user_id == $user->id;
}
}
}
I register the policy in my AuthServiceProvider
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
'App\Story' => 'App\Policies\StoryPolicy'
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
}
}
As I understand it, I should be able to use this policy in my controller. That is what I did.
<?php
namespace App\Http\Controllers;
use App\Storyblock;
use App\User;
use Illuminate\Http\Request;
use App\Category;
use App\Story;
class StoryController extends Controller
{
public function __construct(){
$this->middleware('auth')->except('show');
}
// GET shows the story page
public function show(Story $story) {
$this->authorize('view',$story);
return view('story.show', compact('story'));
}
}
this however always result in a 403
I've tried many things, changing up the way the policies are set, changing the logic dd'ing if all is correct. After 4 hours of lookign online I failed to come up with an answer.
Also, in my phpStorm I noticed that my policy files are indicated red with no usages over the entire project. This makes me think that I somehow fail to import them in my AuthServiceProvider
i don't see all your code but you get this message when you want to access of lavarel resouce and you don't have the scrf token make sure all your view or on the app view header you have this
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
i think you just try to get a resource without this then it just tell you don't have access of this one.
You have specified that the show method isn't going to have the auth middleware assigned, so there may not be an authenticated User. From the Policy documentation:
"By default, all gates and policies automatically return false if the incoming HTTP request was not initiated by an authenticated user"
You will need to continue reading the Policy documentation for how to handle the lack of an authenticated user, guest.
Laravel 5.7 Docs - Authorization - Writing Policies - Guest Users
Related
I have a boilerplate Laravel app, with a model generated with the cli command php artisan make:model Post -a --api to make an API controller, with form request and policies.
The Laravel Policy Authorisation docs doesn't seem to make it clear what to do with both a Policy and FormRequest. Do I call the policy class inside the FormRequest? Or ignore the policies for store/update?
How do I use auth policies with FormRequests for my API controller?
Version
Laravel 9
Although its not told directly in the docs. You can use the policy inside the authorize() method in a Form Request :
Authorization Using Model
class UpdatePostRequest extends FormRequest
{
public function authorize() : bool
{
return $this->user()->can(
'update', $this->post
);
}
}
Controller
class PostController
{
public function update(UpdatePostRequest $request, Post $post)
{
// your code here
}
}
So Instead of using $this->authorize('update', $post) inside the controller you can directly put it inside the FormRequest.
Hope it helps : )
Docs didn't make it clear, posting incase anyone else is struggling. Example for User model, UserPolicy and UserController.
First, add the Policy class in AuthServiceProvider.
App\Providers\AuthServiceProvider
/**
* The policy mappings for the application.
*
* #var array<class-string, class-string>
*/
protected $policies = [
User::class => UserPolicy::class,
];
Second, use authorizeResources in the controller to auto map policies to the api controller. See here for what the policy -> controller maps to
// App\Http\Controllers\UserController
use App\Models\User;
use Illuminate\Http\Request;
use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
class UserController extends Controller
{
/**
* Create the controller instance.
*
* #return void
*/
public function __construct()
{
// Sets up user policy for this controller
$this->authorizeResource(User::class, 'user');
}
...
}
Last, DELETE the authorize section from the FormRequests
// App\Http\Requests\UpdateUserRequest
class UpdateUserRequest extends FormRequest
{
// DELETE the auth part below, otherwise it'd mess up using policies.
// I'm pretty sure this takes precedence over policies
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
//public function authorize()
//{
//return true;
//}
}
Now the policies set in UserPolicy will be used as auth guards for the User Controller.
I am running laravel 8 and this site has been upgraded since laravel 5.2 I believe. Currently I have an admin section and when the session times out it goes to /login. I also have another user section where login is used. I am looking for a way to control where the user is redirected based on the url. If they are /admin/* I want to redirect to /admin/login.
My problem is I can not find where this is controlled. I have tried a variety of ways. Looking at the docs (https://laravel.com/docs/8.x/authentication#redirecting-unauthenticated-users) it says I can change the redirectTo function in /App/http/Middleware/Authenticate.php. Issue is I did not have an Authenticate file. I created one and copied the Authenticate from the vendor src file and just tried to do a dd() on the construct method but it just skips past it so when checking where to send them it does not seem to use this file. If I do the same in the vendor folder version it will dump out.
I know I should not edit any code in the vendor folder as it will get overridden with an upgrade so my question is how/where do I edit this redirectTo function.
I think you should check the App\Http\Kernal.php and confirm if the $routeMiddleware array has "Authenticate" middleware or not?
App\Http\Kernal.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
// ...
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* #var array
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
// ...
]
}
and you can update the Authenticate as follow where we can check the request URL.
App\Http\Middleware\Authenticate.php
<?php
namespace App\Http\Middleware;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* #param \Illuminate\Http\Request $request
* #return string|null
*/
protected function redirectTo($request)
{
// Or we can check the particular segment of the URL.
if (str_contains($request->url(), 'admin')) {
return route('admin/login');
} else {
return route('login');
}
}
}
I'm trying to executing a function in every page and I do that in AppServiceProvider.php in boot() I dependent on Auth class but Auth::check() always return false
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Auth;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
dd(Auth::check());
}
}
From the Laravel Docs
Service providers are truly the key to bootstrapping a Laravel application. The application instance is created, the service providers are registered, and the request is handed to the bootstrapped application. It's really that simple!
Once the application has been bootstrapped and all service providers have been registered, the Request will be handed off to the router for dispatching. The router will dispatch the request to a route or controller, as well as run any route specific middleware.
and since Auth and Session are updated / initialized using a middleware, it means that you can't access to it from a Service Provider.
you can only bind data to views in your service providers using callbacks that are called when the view is rendered ( it means that the server is already preparing the response )
View::composer('is_authenticated', Auth::check());
Maybe Auth is not load on before AppServiceProvider. Because in Controllers Auth::check() work well. So i think using Auth::check() in AppServiceProvider is very bad idea. AppServiceProvider intended to register and bootstrap services, maybe there a better place for Auth::check() in you app?
you need view composer for this.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Auth;
use DB;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->composer('*', function ($view)
{
if (Auth::check()) {
}
});
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
To correctly protect a route for only authorised users, you should use ->middleware('auth') on your route.
https://laravel.com/docs/5.8/authentication
Also I would suggest updating your question to include the Laravel version you are using.
I am building a store so i could learn laravel.
Like most stores, users can add items to a cart but cannot checkout until they register.
How do i have the same route return a user name when authorized and a nothing when an authorized.
This seemed very easy to me at first:
#if(Auth::guest())
Nothing || or login/register buttons
#else
{{ Auth::user()->name }}
#endif
That works well when you have content that should only be visible to loyal users but for a store, you need users to see whats there to offer.
The problem is that, in my home controller, i need to add middleware auth in the constructor function so that Route::get('/',HomeController#index); returns a view and in the view use #if(Auth::guest()) ..., but adding this middleware means this route is not accessible if the user is not Authenticated and without it you get this issue.
So how do i have the same root route with Authenticated user data(if authenticated) without blocking the route from unauthenticated users?
If i am understanding what you are asking (Though i believe i dont quite fully get what you mean).
You want to use the Auth::user() or Auth::check() throughout your views? This should be available out of the box especially when you have used php artisan make:auth.
One way to achieve this would be to use view->share() in a service provider on the boot method, This will then make the $user variable or $isSignedIn variable available in all views.
For example in your App\Providers\AppServiceProvider
namespace App\Providers;
use App\User;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Auth;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
view()->share('isSignedIn', Auth::check());
view()->share('user', Auth::user() ?: new User());
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
}
If this is not going to help let me know and i can help towards getting the outcome you need.
- Update
On your HomeController can you try:
use App\User;
use Illuminate\Support\Facades\Auth;
and in your index() method can you add:
if(Auth::user()){
$user = Auth::user();
}else{
$user = new User();
// or you can use:
$user = Auth::guest();
// If you use $user = Auth::guest() you can remove the Use App\User;
}
return view('home', compact('user'));
See if that does anything for you?
I have been following the instructions here to install this custom provider for socialite on an install of Laravel 5.3
I am redirected back with an access token and everything within a user object.
I am wondering however what the best way to store that information to authenticate them into the app or if a user doesn't exist to place them into a new one.
Here is my controller.
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Socialite;
use App\User;
class AuthController extends Controller
{
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Redirect the user to the Envato authentication page.
*
* #return Response
*/
public function redirectToProvider()
{
return Socialite::with('envato')->redirect();
}
/**
* Obtain the user information from Envato.
*
* #return Response
*/
public function handleProviderCallback()
{
$user = Socialite::with('envato')->user();
}
}
Any ideas?
what I do is create a user entry for them where the email(in case it was not returned from envato) and password are set to null, and create a social_profile entry that belongs to that user, which has his access token and envato id and any extra info.
now there are multiple test cases there... one example is if he signs up later with email/password. you make him validate by email(like reset password).