laravel 4.2. user permissions and hiding link source - laravel

I am a total newbie with Laravel and learning it now for a week. I have some basic questions that I can't find an answer to. Next week I will start with developing CRM system and I need some info from experienced developers who could tell me is the approach I am attending to make a good one.
I will need some authentication system, like 4 groups of users (Admin, Basic, Manager, Office) where Manager and Admin will add the Basic users. There will be few view and features and every groups will have defined access to each view and feature. Since few days I am searching for packages, watching the tutorials and learning. I found an interesting package for which I think it could help me with this user-group-permission things.The package is Sentry. Could this help me with my requirements?
What is the case when for example I have a user in group Basic and he deletes for example some comment with the button. On the left side down in the browser the user can see the link to this comment when he hovers the link. For example www.test.com/comments/345/delete where the id is 345. What if user types that with another id, that means he can delete another comment. I found some suggestions on how to solve this, to make it with jQuery and javascript so the link wouldn't be shown and POST would be made with for example with AJAX. But since I am a newbie, I am thinking how much time would this take and is this a good approach at all? Could package Sentry from 1. question help me with the permission on what route each group can access?
Any help or advice would be appreciated.

Sentry does what you want, yes. Here's a question with some answers explaining the permissions part.
The visible link part can be avoided by doing a POST request instead of a GET request.
When you open your form, you add a method attribute.
Form::open(array('url' => 'foo/bar', 'method' => 'post'))
A GET request will put the parameters in the URL, hence the visible ID. Using a POST request will put the parameters in the headers, thus hiding it from the URL.
An example could be deleting a comment. A GET request could look like this:
http://www.example.com/comments/delete/1
And the parameters would be defined in your method signature:
public function getDelete ($id) {
Comment::find($id)->delete();
}
Where the POST equivalent would be
http://www.example.com/comments/delete
And the parameters would be defined in your Input class, you would get them using the get method
public function postDelete() {
Comment::find(Input::get('id'))->delete();
}

1) The best package to help you with that is Sentry indeed.
2) To make sure an user can delete only his comments you can do something like this (but there are more solutions either you do it with Ajax or not):
public function destroy($id) {
$user = Sentry::getUser();
$comment = Comment::find($id);
if($comment) {
if($comment->user_id != $user->id) {
return Response::back(); // optional message: Permission denied!
}
$comment->delete();
return Response::back(); // optional with message: Deleted!
}
return Response::back(); // optional message: Comment not found!
}
You can use Sentry in this case to get the logged in user and check for user id. I think you should let user delete their own comments always but if you need special roles (Admins for example) to be able to delete any comment, or special permission comments.delete (For some Managers) - you can use Sentry as well:
public function destroy($id) {
$user = Sentry::getUser();
$comment = Comment::find($id);
if($comment) {
if($comment->user_id != $user->id && !$user->hasRole('Admin') && !$user->hasPermission('comments.delete'))) {
return Response::back(); // optional message: Permission denied!
}
$comment->delete();
return Response::back(); // optional with message: Deleted!
}
return Response::back(); // optional message: Comment not found!
}
A nicer way of making the DELETE thru a Form request check this:
Laravel RESTfull deleting

Related

Redirect using get and then redirect to the response

Lets start off with the code
if($request->berbix == true || $request->berbix == 'true'){
THIS IS WHERE I NEED THE LOGIC TO GO
}
else {
session()->flash('flash.banner', 'Profile updated!');
session()->flash('flash.bannerStyle', 'success');
return Redirect::route('dashboard');
}
In the if statement this is what needs to happen.
user needs to be send to /verification/create with their user model
When that is completed, it will provide a URL
user then needs to be redirected to said URL
I know this should be simple but I am having a HECK of a time wrapping my head around the simple logic. The main thing I am struggling with (and I know why, but don't know how to solve it), is when I do for example Http::get() it isnt sending it as the user so the request doesn't know the user info
Any help either a solution or a nudge on what I need to do would be very nice right now!
While I would still consider redirecting to a different route/controller to handle this, since you said you want it all in one place, it is possible to call controller methods directly and retrieve a response without leaving the current method or creating another HTTP request.
You could do something like this.
$url = app()->call('App\Http\Controllers\VerificationController#create', [
'user' => auth()->user()
]);
if ($url) {
return redirect($url);
}

How to handle data before delete from model in Laravel?

I have the following method:
public function destroy($id)
{
$id = \JWTAuth::parseToken()->authenticate();
$offer = Offer::findOrFail($id);
$offer->delete();
return response()->json(["offer" => $offer]);
}
How handle data before deleting? I need to check if user has permit to delete data or not
When you use the authenticate() method, the user model is retrieved so it means the id you have is not an id but a User. Have you checked the documentation of JWT Because first and foremost you have to retrieve the user and this is sufficient:
$user = \JWTAuth::parseToken()->authenticate();
Then if you have a field for example in your users table to tell if the user have the right say admin which can be 1 or 0 then you can do the following:
if($user->admin == 1)
{
$offer = Offer::findOrFail(1); //say id
$offer->delete();
return response()->json(["offer" => $offer]);
}
return response()->json(['error' => 'you dont have the right to delete this'], 403);
Just a little scratch on the idea, but my best advice is to do some searches on how JWT is implemented, I am pretty sure you will find tons of them online.
I would recommend using the Model's delete event:
https://github.com/laravel/framework/blob/5.2/src/Illuminate/Database/Eloquent/Model.php#L1122
and handle it.
This will guarantee that if you use the delete method on a model, you always check permissions.

Controller Authorization not working in laravel 5.2

I want to authorize my delete action using the Controller Authorization. Instead of using DELETE, I am sending the delete directly to the controller. Student can be deleted by instructor.
I followed the approach as explained at -
Controller Authorization
Below is my function -
public function deleteProfile(Student $student)
{
//authorize the request
$this->authorize('deleteProfile',$student); //$student is valid Student object
$student->delete();
}
When I try to delete it gives me exception -
HttpException in Handler.php line 104: This action is unauthorized.
I found this approach simple so, tried to implement it. Is there anything which I am missing ?
Correct this file with your xxxPolicy.php
Add the intval() in case. And it`s work.
ProjectPolicy.php :
public function destroy(User $user, Project $project)
{
return $user->id === intval($project->user_id;
}
Register a gate policy where you put the logic of who can delete the request. If by that logic the current user can delete, it will be deleted else it will throw a not authorized exception like you did.
Or else you can manually give authorization on your controller method for the user
$this->authorizeForUser($user, 'deleteProfile',$student);
as per documentation "The Gate will automatically return false for all abilities when there is not an authenticated user". So before doing any authorization, please check Auth::user() if it returns a currently authenticated user."

Laravel 5 and Socialite - New Redirect After Login

Another newb question here, but hopefully someone can shed some light:
I am using Socialite with Laravel 5, and I want to be able to redirect the user to a page on the site after they have logged in. The problem is that using
return redirect('any-path-I-put-here');
simply redirects back to 'social-site/login?code=afkjadfkjdslkfjdlkfj...' (where 'social-site' is whatever site is being used i.e. facebook, twitter, google, etc.)
So, what appears to me to be happening is that the redirect() function in the Socialite/Contracts/Provider interface is overriding any redirect that I attempt after the fact.
Just for clarification, my routes are set up properly. I have tried every version of 'redirect' you can imagine ('to', 'back', 'intended', Redirect::, etc.), and the method is being called from my Auth Controller (though I have tried it elsewhere as well).
The question is, how do I override that redirect() once I am done storing and logging in the user with socialite? Any help is appreciated! Thank you in advance.
The code that contains the redirect in question is:
public function socialRedirect( $route, $status, $greeting, $user )
{
$this->auth->login( $user, true );
if( $status == 'new_user' ) {
// This is a new member. Make sure they see the welcome modal on redirect
\Session::flash( 'new_registration', true );
return redirect()->to( $route );// This is just the most recent attempt. It originated with return redirect($route);, and has been attempted every other way you can imagine as well (as mentioned above). Hardcoding (i.e., 'home') returns the exact same result. The socialite redirect always overrides anything that is put here.
}
else {
return redirect()->to( $route )->with( [ 'greeting' => $greeting ] );
}
}
... The SocialAuth class that runs before this, however, is about 500 lines long, as it has to determine if the user exists, register new users if necessary, show forms for different scenarios, etc. Meanwhile, here is the function that sends the information through from the Social Auth class:
private function socialLogin( $socialUser, $goto, $provider, $status, $controller )
{
if( is_null( $goto ) ) {
$goto = 'backlot/' . $socialUser->profile->custom_url;
}
if( $status == 'new_user' ) {
return $controller->socialRedirect($goto, $status, null, $socialUser);
}
else {
// This is an existing member. Show them the welcome back status message.
$message = 'You have successfully logged in with your ' .
ucfirst( $provider ) . ' credentials.';
$greeting =
flash()->success( 'Welcome back, ' . $socialUser->username . '. ' . $message );
return $controller->socialRedirect($goto, $status, $greeting, $socialUser);
}
}
I managed to workaround this problem, but I am unsure if this is the best way to fix it. Similar to what is stated in question, I got authenticated callback from the social media, but I was unable to redirect current response to another url.
Based on the callback request params, I was able to create and authenticate the user within my Laravel app. It worked good so far but the problems occured after this step when I tried to do a return redirect()->route('dashboard');. I tried all the flavours of redirect() helper and Redirect facade but nothing helped.
The blank page just stared at my face for over 2 days, before I checked this question. The behaviour was very similar. I got redirect from social-media to my app but could not further redirect in the same response cycle.
At this moment (when the callback was recieved by the app and user was authenticated), if I refreshed the page manually (F5), I got redirected to the intended page. My interpretation is similar to what's stated in this question earlier. The redirect from social-media callback was dominating the redirects I was triggering in my controller (May be redirect within Laravel app got suppressed because the redirect from social-media was still not complete). It's just my interpretation. Experts can throw more light if they think otherwise or have a better explaination.
To fix this I issued a raw http redirect using header("Location /dashboard"); and applied auth middleware to this route. This way I could mock the refresh functionality ,redirect to dashboard (or intended url) and check for authentication in my DashboardController.
Once again, this is not a perfect solution and I am investigating the actual root of the problem, but this might help you to move ahead if you are facing similar problem.
I believe you are overthinking this. Using Socialite is pretty straight forward:
Set up config/services.php. For facebook I have this:
'facebook' => [
'client_id' => 'your_fb_id',
'client_secret' => 'your_fb_secret',
'redirect' => '>ABSOLUTE< url to redirect after login', //like: 'http://stuff'
],
Then set up two routes, one for login and one for callback (after login).
In the login controller method:
return \Socialize::with('facebook')->redirect();
Then in the callback function
$fb_user = \Socialize::with('facebook')->user();
// check if user exists, create it and whatnot
//dd($fb_user);
return redirect()->route('some.route');
It should be pretty much similar for all other providers.
We are using the Socialite login in our UserController as a trait. We simply overrode the AuthenticatesSocialiteLogin::loginSuccess() in our controller.
use Broco\SocialiteLogin\Auth\AuthenticatesSocialiteLogin;
class UserController extends BaseController
{
use AuthenticatesSocialiteLogin;
public function loginSuccess($user)
{
return redirect()->intended(url('/#login-success'));
}
....

Laravel 4 route-model binding exceptions doesn't work despite docs and examples

I read a lot about Laravel4 Route-model binding (L4 docs, tutorials, etc.) but still exceptions (i.e. the model is not found) don't work for me
These are my basic files
routes.php:
Route::model('game', 'Game', function(){
// override default 404 behavior if model not found, see Laravel docs
return Redirect::to('/games');
});
...
Route::get('/games/edit/{game}', 'GamesController#edit');
GamesController.php
class GamesController extends BaseController {
...
public function edit(Game $game){
return View::make('/games/edit', compact('game'));
}
}
Pretty straight, but I get this error: Argument 1 passed to GamesController::edit() must be an instance of Game, instance of Illuminate\Http\RedirectResponse given
If I type http://mysite.dev/games/edit/1 all is fine (model with ID = 1 exists)
If I type http://mysite.dev/games/edit/12345 (no model with that ID) the ugly error above is triggered instead of the redirect I specified
I also looked at this (the bottom part where a Redirect closure is suggested: that is just what I am doing!) but no way to make it work: laravel 4 handle not found in Route::model
What's wrong with it? Please any help?
Thanks in advance
In Route::model you declare which variable will be a model instance, you shouldn't use it to do a redirection that way. Instead of that, specify that $game is of type Game and then work with your routes:
Route::model('game', 'Game');
...
Route::get('/games/edit/{game}', 'GamesController#edit');
Then if you access to /games/edit/3 GamesController::edit will receive an instance of Game class whose id=3
I ended up by setting a general "Not Found" error catcher, like this:
// routes.php
App::error(function(Symfony\Component\HttpKernel\Exception\NotFoundHttpException $e) {
return Response::make('Not Found', 404);
});
...
Route::model('game', 'Game');
...
Route::get('/games/edit/{game}', 'GamesController#edit');
What I understand is that if I want a custom redirect and not a general 404 page (i.e. take the user to games' list if model not found), I CAN'T use the route-model-binding
In other words, I have to use Route::get('/games/edit/{id}', 'GamesController#edit'); and then do my application logic inside the 'edit' method:
public function edit($id){
$game = Game::findOrFail($id);
// if fails then redirect to custom page, else go on saving
}
I'm very new to Laravel, but as far as I can see this has nothing to do with the closure, but with the use of "Redirect::to" inside that closure. Using "App::abort( 404 );" works.

Resources