Laravel 5 and Socialite - New Redirect After Login - laravel

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'));
}
....

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);
}

Pass variable from middleware to view via controller in Laravel 5.2

Hi I am trying to do the following in Laravel 5.2.
Summary: Pass some variables from middleware to view, via controller
Detailed: When a client is logged in, no matter what route they want, we need to check if they have completed all "setup steps" (each step refers to a different route, e.g. one could be company info, another could be product settings, etc). If they have completed all setup steps, then let them proceed to their chosen route, otherwise we redirect to the appropriate "setup steps" route, whichever one they haven't completed yet.
All client controllers run the same middleware, called NonSuperAdmin. I would like to put the checking of "setup steps" in this middleware, and redirect from there as appropriate. If client is redirected to a setup route by this middleware, we need the "incompleteSetupTasks" collection to be passed on to the relevant view, via the appropriate setup steps controller method.
Is this possible? Any help is much appreciated.
In the middleware use session handler
if($condition === true){
$data = [ //your content ];
Session::flash('your_key', $data);
}
next($request);
This data will also be available in your controller and in view
This is how you can access data in controller
public function yourControllerAction($request)
{
$somevariable = Session::get('your_key');
$viewdata = [
'content' => $somevariable
]
return view('yourview', $viewdata);
}
Or directly access the session data in view
//inblade
<p>
Your html content
#foreach(Session::get('your_key' as $data)
//your stuff
#endif
</p>
May be use Laravel Session to store and read values?
You can pass your setup steps to get or post parameters and check in routes with middleware if these parameters are empty:
Route::get('post/{setup1?}/{setup2?}', ['middleware' => 'role:admin', function ($setup1, $setup2) {
if(empty($setup1) and empty($setup2)){
// do smth
} else {
// redirect
}
}]);
Question marks mean, that they are optional parameters. Hope it was helpful.

Laravel 5.2 4 rolle

I need help how to make laravel 5.2 authenticate with 4 rolls?
guest
registered
support
admin
I make something but every time I get
ERR_TOO_MANY_REDIRECTS.
Route::group(['middleware' => ['web','isAdmin']], function () {
Route::get('/', function(){
return view('admin');
});
});
Route::group(['middleware' => ['web','isSupport']], function () {
Route::get('/support', function(){
return view('support');
});
});
Middleware
public function handle($request, Closure $next)
{
if (Auth::user()->role == '3') {
return $next($request);
}
if(Auth::guest()){
redirect('login');
}else
return redirect('/');
}
}
If I assume, you add isAdmin middleware to path /. isAdmin middleware is checking that user have a proper role (role with id === 3). If not, then redirect to /.
So only user with role 3 can access to path / but system still try redirect to this path. Infinite loop.
Yes, #grzegorz has the correct answer already posted on here I believe. But I will try to explain it clearly.
So in your route for the root of your application ('/') you tell Laravel to process middleware to authenticate users. This in and of itself is not unusual. The middleware runs a function to see if a user basically has level 3 authority and if they do then you return the request url (which is also '/' and the process continues in an infinite loop, because they are sent to the '/' url, then it processes and returns the same url again, causing it to process middleware again, going forever. This is why you are getting an error saying that there are too many redirects, because it redirects a whole bunch of times with no end in sight and eventually Laravel stops it for you and returns an error.
How to fix this problem?
Easy, you have a good start already. But what I would do is that when you check to see if a user has auth level 3 and they do, then simply return true. There is no need to return the requesting url, because this is middleware, so its running when someone requests a URL. So the purpose of your middleware would be to return true meaning "don't do anything, just continue". Then if the user does not have authority level 3, then you would want to redirect them away from this page. Do an actual redirect though (as opposed to returning a url string like you are now). So you would want to do something like this:
return redirect()->route('login');
You could also add some flash data to this with an error message to display to the user something telling them that they do not have access to this route.
Last note:
It would be strange to only allow high level authority users to be the only ones that can access a homepage. Maybe this is what you want, but it seems weird so I wanted to mention it in case it is unintended. What I wonder you are doing is maybe trying to display different information on the homepage depending if someone is logged in or not. if this is the case, then you don't want to use middleware, you want to move this to the controller and then conditionally add html for logged in users or something like that.

laravel 4.2. user permissions and hiding link source

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

How to forward argument for redirect::route->with when hitting an auth filter using Laravel?

I have the following problem:
After a user is created and the user has confirmed her email.
I would like the user to login,
I use the following code to do that:
Redirect::route('login-forward')->with('alert_message', ...)
the alert messages simply states that everything went well, and I would like her to login.
login-forward is protected with an before filter, that runs the actual login form,
When the user then logs in sucesfully, she is brought back to login-forward, whic then puts the user at her personal landing page.
the code for the route 'login-forward is:
Route::get('my-login', array(
'as' => 'login-forward',
'before' => 'auth',
function ()
{
$user = Auth::user();
switch ($user->role)
{
case 'Administrator':
return Redirect::route('admin_dashboard');
case 'FreeUser':
return Redirect::route('cs-dashboard');
default:
return Redirect::route('/');
}}));
the problem is, the ->with('alert_message',...) is not seen by the real login route called by the before filter.
How do I solve this?
The best approach is to let the user logs in automatically when the email is confirmed, if the user confirms the account creation then when you find that user is valid then you may log in that user using something like:
// $user = Get the user object
Auth::login($user);
Also you may use:
Session::put('alert_message', ...);
Redirect::route('login-forward');
Then when the user logs in for the first time, just get the message from Session using:
// Get and show the alert_message
// from session and forget it
#if (Session::has('alert_message'))
{{ Session::pull('alert_message') }}
#endif
So, when you pull the message from the Session to show it, the message will no longer be available in the Session or you may use Session::reflash() to flash the flashed session data for another subsequent request until you get in the page where you want to show the message.
The best choice is - you can make forward to login form without redirect from method of controller for url of personal page.
return Route::dispatch(Request::create('login'))->getOriginalContent();

Resources