google account login for the first time displays error - authentication

I am trying to login the user with google account in my application. I am having a problem when the user is logged in for the first time with google account in my app it shows this error:
Argument 1 passed to Illuminate\Auth\Guard::login() must implement interface Illuminate\Auth\UserInterface, null given
In my controller I have this:
public function loginWithGoogle() {
// get data from input
$code = Input::get('code');
// get google service
$googleService = Artdarek\OAuth\Facade\OAuth::consumer("Google");
if (!empty($code)) {
// This was a callback request from google, get the token
$token = $googleService->requestAccessToken($code);
// Send a request with it
$result = json_decode($googleService->request('https://www.googleapis.com/oauth2/v1/userinfo'), true);
$user = User::whereEmail($result['email'])->first(['id']);
if (empty($user)) {
$data = new User;
$data->Username = $result['name'];
$data->email = $result['email'];
$data->google_id = $result['id'];
$data->first_name = $result['given_name'];
$data->last_name = $result['family_name'];
$data->save();
}
Auth::login($user);
return Redirect::to('/');
}
// if not ask for permission first
else {
// get googleService authorization
$url = $googleService->getAuthorizationUri();
// return to facebook login url
return Redirect::to((string) $url);
}
}
I know the problem is with Auth::login($user); as insert is performed at the same time with Auth::login($user); and it doesn't find data from database for the first time, but I don't know how to avoid this error and instead redirects to the main page even when the user is logged in for the first time. After this error the user is logged in, but how to avoid this?

Without knowing whether the rest of the code works, you definitely have a problem here:
if (empty($user)) {
$data = new User;
(...)
$data->save();
}
Auth::login($user);
When you're done creating your user, the $user variable is still empty. Your user is actually called $data. You should either rename the variable, or do the login with $data instead. Hopefully, that's enough to make the code work. :)

Related

How to make friends Facebook Log in code with Google log in code

I have two snippets of code that are each responsible for logging in from their social networks are Facebook and Google.
//GOOGLE
if(isset($_GET['code'])) {
$token = $google_client->fetchAccessTokenWithAuthCode($_GET["code"]);
//This condition will check there is any error occur during geting authentication token. If there is no any error occur then it will execute if block of code/
if (!isset($token['error'])) {
//Set the access token used for requests
$google_client->setAccessToken($token['access_token']);
//Store "access_token" value in $_SESSION variable for future use.
$_SESSION['access_token'] = $token['access_token'];
//Create Object of Google Service OAuth 2 class
$google_service = new Google_Service_Oauth2($google_client);
//Get user profile data from google
$data = $google_service->userinfo->get();
if (!empty($data['sub'])) {
$_SESSION['user_id'] = $data['sub'];
}
if (!empty($data['given_name'])) {
$_SESSION['user_name'] = $data['given_name'] . " " . $data['family_name'];
}
if (!empty($data['email'])) {
$_SESSION['user_email_address'] = $data['email'];
}
if (!empty($data['picture'])) {
$_SESSION['user_image'] = $data['picture'];
}
}
}
//FACEBOOK
$facebook_helper = $facebook->getRedirectLoginHelper();
if(isset($_GET['code'])) {
if (isset($_SESSION['access_token'])) {
$access_token = $_SESSION['access_token'];
} else {
$access_token = $facebook_helper->getAccessToken();
$_SESSION['access_token'] = $access_token;
$facebook->setDefaultAccessToken($_SESSION['access_token']);
}
$graph_response = $facebook->get("/me?fields=name,email", $access_token);
$facebook_user_info = $graph_response->getGraphUser();
if (!empty($facebook_user_info['id'])) {
$_SESSION['user_image'] = 'http://graph.facebook.com/' . $facebook_user_info['id'] . '/picture';
}
if (!empty($facebook_user_info['id'])) {
$_SESSION['user_id'] = $facebook_user_info['id'];
}
if (!empty($facebook_user_info['name'])) {
$_SESSION['user_name'] = $facebook_user_info['name'];
}
if (!empty($facebook_user_info['email'])) {
$_SESSION['user_email_address'] = $facebook_user_info['email'];
}
} else {
// Get login url
$facebook_permissions = ['email']; // Optional permissions
$facebook_login_url = $facebook_helper->getLoginUrl('https://2goe.com/demo/'.$lang.'/home/', $facebook_permissions);
}
When they are together, then:
When you click Google log in, redirectURL responds with server error 500.
And Facebook does not return user data, which is requested in the code.
But if, for example, you delete the code of one of the social networks, it individually works fine. I myself tried to somehow paint 2 codes into one code, but to no avail. I also split them into different files, but this also did not bring any results.
Can you please help me somehow combine them correctly so that there are no such conflicts between them.
The issue you are having is that you are setting things with the same session names. $_GET['code'] could be facebook or google there is no way for you to know which one it is.
The easiest solution would be to run the google code first. Then alter the if statement for Facebook a little.
If you do something like this the code for facebook will look for a code find a code but it will also look for an error from Google. If google spit back an error then you try the code with facebook. If it did not return an error then you know the code was most likely used by Google.
if(isset($_GET['code'] && isset($token['error'])) {

LARAVEL 5: Need to keep query string after auth redirects

I have a link I am sending via email. For example, www.swings.com/worker?id=3382&tok=jfli3uf
In this case I want the person to click the link, get sent to the login page(which it does) and then be directed to a controller method WITH the $id and $tok variables. I can't get that part to work. Any ideas? I am only using the RedirectIfAuthenticated class and this is what it looks like:
public function handle($request, Closure $next)
{
$user = $request->user();
if ($this->auth->check()) {
if($user && $user->hasRole('worker'))
{
return redirect('worker');
}
return redirect('home');
}
return $next($request);
}
hasRole is a method I created in the User model that checks the role of the logged in user
You can flash data to the session when redirecting by chaining the with() method:
// in your handle() method:
return redirect('home')->with($request->only('id', 'tok'));
// then in home controller method:
$id = session('id');
$tok = session('tok');
AFTER SOME HOURS I WAS ABLE TO HAVE A SOLUTION:
ReturnIfAuthenticated wasn't changed. I just added the following within my controller that this link should go to:
for instance, the route would be:
Route::get('worker', 'WorkerController#methodINeed');
Within this method:
public function methodINeed() {
$id = Input::get('id');
$tok = Input::get('tok');
// Do what I need this variables to do
}
What I didn't understand and what could not be properly understood is that the auth controller in Laravel 5 is triggered when a user is a guest it will still redirect to the actual method with all its original data once auth is successful. Hope this is helpful.

viaRemember not work - laravel

Auth :: attempt works perfect, but when you pass the second parameter "true" apparently does not care or does not recover with viaRemember
viaRemember fails to work, check this
controller User
`$`userdata = array(
'email' => trim(Input::get('username')),
'password' => trim(Input::get('password'))
);
if(Auth::attempt(`$`userdata, true)){
return Redirect::to('/dashboard');
}
view 'dashboard', always show 777
#if (Auth::viaRemember())
{{666}}
#else
{{777}}
#endif
I have hit the same obstacle, so looking into the code one can see that viaRemember is not meant to be used as a function to check if the user was logged into the system in one of all the ways a user can be logged in.
'viaRemember' is meant to check if a user was logged into the system specifically via the `viaRemember' cookie.
From what I gather, authentication of user is remembered in two ways:
a via remember cookie.
The cookie value is compared to the via remember field in the users table.
a session cookie.
The cookie value is used in the server to get the session from the
session store. On the session object from the store there is data attached. One of the
data items is the user id connected to the session. The first time
the session was created, the system attached the user id to the data
of the season.
In Illuminate\Auth\Guard class:
public function user()
{
if ($this->loggedOut) return;
// If we have already retrieved the user for the current request we can just
// return it back immediately. We do not want to pull the user data every
// request into the method because that would tremendously slow an app.
if ( ! is_null($this->user))
{
return $this->user;
}
$id = $this->session->get($this->getName());
// First we will try to load the user using the identifier in the session if
// one exists. Otherwise we will check for a "remember me" cookie in this
// request, and if one exists, attempt to retrieve the user using that.
$user = null;
if ( ! is_null($id))
{
$user = $this->provider->retrieveByID($id);
}
// If the user is null, but we decrypt a "recaller" cookie we can attempt to
// pull the user data on that cookie which serves as a remember cookie on
// the application. Once we have a user we can return it to the caller.
$recaller = $this->getRecaller();
if (is_null($user) && ! is_null($recaller))
{
$user = $this->getUserByRecaller($recaller);
}
return $this->user = $user;
}
The getUserByRecaller function is called only if the session cookie authentication did not work.
The viaRemember flag is only set in the getUserByRecaller function. The viaRemember method is only a simple getter method.
public function viaRemember()
{
return $this->viaRemember;
}
So in the end, we can use Auth::check() that does make all the checks including the viaRemember check. It calls the user() function in the Guard class.
It seems also the viaRemember is only an indicator. You need to do a type of Auth::check() the will get the process of authentication started and so the user() function will be called.
It seems that your project is on Laravel 4.0 but viaRemember() is added in Laravel 4.1! So that's expected.
in config\session.php file change the 'expire_on_close' = false to true and once you close restart your browser, it must be ok.

How do get a new Facebook access token invisibly when my current one expires? (Windows 8 App C#)

Within my app (following various documentations) the user is able to login in to facebook via a dedicated login page. From this, the access token is given and the I save it. The thing is to get the token this way (using await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, loginUri, new Uri(redirectUri));, which seems the automatically show a login screen from facebook, I honestly have no idea how it appears...) means the user has to type their username and password again.
I don't want this to be the case, since I think if the user has logged in once, they shouldn't need to keep typing in their details again and again. However no matter what I've tried I can seem to get a new access token without going through this login screen again.
I've tried methods using the FacebookClient.Get() method, however it just doesn't exist in this version of the SDK. I have no idea what to use in its place, or what I need to send to Facebook to get a response.
So far this is what I have to log in for the first time (pretty much what is on the documentation)
string redirectUrl = "https://www.facebook.com/connect/login_success.html";
try
{
var loginUrl = fb.GetLoginUrl(new
{
client_id = FacebookHandler.FacebookAppId,
redirect_uri = redirectUrl,
scope = FacebookHandler.Permissions,
display = "touch",
response_type = "token"
});
Uri endUri = new Uri(redirectUrl);
WebAuthenticationResult webAuthRes = await WebAuthenticationBroker.AuthenticateAsync(WebAuthenticationOptions.None, loginUrl, endUri);
if (webAuthRes.ResponseStatus == WebAuthenticationStatus.Success)
{
var callbackUri = new Uri(webAuthRes.ResponseData.ToString());
var facebookOAuthResult = fb.ParseOAuthCallbackUrl(callbackUri);
var accessToken = facebookOAuthResult.AccessToken;
if (String.IsNullOrEmpty(accessToken))
{
// User is not logged in, they may have canceled the login
}
else
{
// User is logged in and token was returned
FacebookHandler.AccessToken = accessToken;
LoginSucceeded();
}
}
else if (webAuthRes.ResponseStatus == WebAuthenticationStatus.ErrorHttp)
{
Debug.WriteLine("Error: " + "HTTP Error returned by AuthenticateAsync() : " + webAuthRes.ResponseErrorDetail.ToString());
}
else
{
Debug.WriteLine("Error: " + "Error returned by AuthenticateAsync() : " + webAuthRes.ResponseStatus.ToString());
}
}
catch (Exception ex)
{
//
// Bad Parameter, SSL/TLS Errors and Network Unavailable errors are to be handled here.
//
Debug.WriteLine(ex);
throw ex;
}
On successive launches of the app, after the user as entered their details for the first time, the saved access token could be used, but it soon expires, which throws a FacebookOAuthException. This is where I have tried to invisibly get a new access token, and where its not working.
try
{
await fb.PostTaskAsync(url, argList);
}
catch (FacebookOAuthException exc)
{
Debug.WriteLine(exc.Message);
ValidateLoginUrl(GetLoginUrl());
//Problem is with the ValidateLoginUrl(), which would get an access token from the login url
}
One of the things I've tried was to use TryParseOAuthCallbackUrl(), on the loginUrl that I can get by using FacebookClient.GetLoginUrl() (which is successful), but when I try to parse it it just comes up with an InvalidOperationException, and otherwise no explanation.
What do I have to do in order to get a new access token without the user having to login in again? I have my app ID and secret, and I could probably save the users ID from the initial login for use later(?). Would any of that help do this?

How to get online duration of a user by using session?

In yii I need to store the users _login time,logout time and total duration logged_ Using session.
I am new to session concept. I don know how to retrieve the total logged time, login time, log out time. In session table it stores only id--expire--data
My code for storing session is
protected/config/main.php
'components'=>array(
'session'=>array(
'class' => 'CDbHttpSession',
'connectionID' => 'db',
'sessionTableName' => 'dbsession',
),
),
All working fine but data stored in db are encrypted. So I am unable to retrieve the data I need. One more thing what data is stored in session table.
Alternative way I used without session but that also have problem. I used this for getting login time, logout time and total duration logged
I used a table activity with fields
id,username,user_activity,url,ip,time
Codes to fill datas in table when user login and logout is below
protected/controller/sitecontrollers.php
public function actionLogin()
{
/* log in */
$model=new LoginForm;
// if it is ajax validation request
if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
// collect user input data
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if($model->validate() && $model->login())
{
$activity = new Activity;
$activity->username = Yii::app()->user->id;
//$activity->userId = Yii::app()->user->id;
$activity->user_activity = "1";
$activity->url=$_SERVER['HTTP_REFERER'];
$activity->ip=$_SERVER['REMOTE_ADDR'];
// This breaks the site when log in details are wrong
$activity->save();
if($activity->save())
$this->redirect(Yii::app()->homeUrl);
}
}
// display the login form
if(Yii::app()->user->id==null)
{
$this->render('login',array('model'=>$model));
}
else
{
throw new CHttpException(404,'User already logged in.');
}
}
/**
* Logs out the current user and redirect to homepage.
*/
public function actionLogout()
{
// log
$activity = new Activity;
$activity->username = Yii::app()->user->id;
$activity->user_activity = "0";
$activity->url=$_SERVER['HTTP_REFERER'];
$activity->ip=$_SERVER['REMOTE_ADDR'];
$activity->save();
Yii::app()->user->logout();
if($activity->save())
$this->redirect(Yii::app()->homeUrl);
}
In this way all workin fine but when browser closed the application is logged out and a data not entering in to the database.then the calculation of duration is getting wrong. So only I took the method session but don't know how to use.
i think you will never do such kind of thing corectly but with some mistake (more or less some minutes, depends on your needs).
1. Keeping alive with page requests
You could send alive status to your ajax page actionImAlive and more often you do that, more precisely you will tell how long user session was. If you do that alive thing 1 time in 5 minutes, you will have duration with ~5min mistake.
Add columns t_login, t_last_activity
on User login update t_login and t_last_activity with current timestamp
On every user new page load check if need to update t_last_activity
Main Controller *(components/Controller.php)
public function keepAlive( ) {
User::model()->updateByPk(
Yii::app()->user->id,
// array('t_last_activity' => 'NOW()') //CURRENT_TIMESTAMP
array('t_last_activity' => new CDbExpression('NOW()')) //CURRENT_TIMESTAMP..this working fine
);
}
// Runs after any action in controller
public function afterAction($action) {
self::keepAlive();
parent::afterAction($action);
}
// This action can be reached by ajax every 5min
// if user stays in one page long enaugh
// (write javascript..)
public function actionImAlive() {
self::keepAlive();
}
Above code updates t_last_activity every time user loads new page, but you could do it every 5min by saving last activity timestmap in user session and check it before executing keepAlive() function
Other controllers
All other controllers uses Controller class as parent
SiteController extends Controller
MyController extends Controller
SomeController extends Controller
2. For user display only (calculates duration from login time to now: now() - t_login)
If you want to display this session duration to user (why you should want to do this I don't know, but anyway..) you could just add t_login column to User table and calculate duration time on a fly.
These was top of my head.