Auth::check() and before('auth') = always sql request for every page? - sql

Am I messing with something or does Laravel conduct sql request to grab data from user table even if all i do on specific page is Auth::check() or have before('auth') filter in router? It can not "get" that user is logged in just from session data (login_82e5d2c56bdd0811318f0cf078b78bfc = user_id etc) without
select * from `users` where `id` = ? limit 1
?
There is some security or other risen to not deal just with session data in case of simple checking of user status (i would prefer to make 1 request per session (not per page) to mysql for user data (or else) and than store it in session, and session set to store in memcached or redis and i am wondering can i get that "out of the box"\without serious changes in Authentication system of framework)?

You can keep it's instance in the container when you check it for the first time
App::before(function($request)
{
App::singleton('myApp', function(){
$app = new stdClass();
if(Auth::check()) {
$app->user = Auth::User();
$app->isLogedin = TRUE;
}
else {
$app->user = false;
$app->isLogedin = false;
}
return $app;
});
$myApp = App::make('myApp');
View::share('myApp', $myApp);
});
Now in every view, you can check like this
#if($myApp->isLogedin)
Hello {{ $myApp->user->user->user_name }}!
#endif
In any controller, you can use it like
$myApp = App::make(myApp); // Get it from the container
// do whatever you want to do
So, you can check logged in or not and also can use Auth::user() object using $myApp->user.

Related

How to determine timestamp of last API request by user in parse server?

Is there a way to determine the timestamp of the last app launch or log the timestamp the last API request from a user on parse server, on the server side without adding code to the client?
To do this without modifying the client, you could think of a request your clients always perform, like a find query and then set a hook on your server like this one from the docs.
Parse.Cloud.beforeFind('MyObject', function(req) {
let query = req.query; // the Parse.Query
let user = req.user; // the user
let triggerName = req.triggerName; // beforeFind
let isMaster = req.master; // if the query is run with masterKey
let isCount = req.count; // if the query is a count operation (available on parse-server 2.4.0 or up)
let logger = req.log; // the logger
let installationId = req.installationId; // The installationId
});
Then just persist the data you want somewhere like the user model and save it.

google account login for the first time displays error

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. :)

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.

HTML5 history API to reduce server requests

I am trying to develop a search filter and making use of the HTML5 history API to reduce the number of requests sent to the server. If the user checks a checkbox to apply a certain filter I am saving that data in the history state, so that when the user unchecks it I am able to load the data back from the history rather than fetching it again from the server.
When the user checks or unchecks a filter I am changing the window URL to match the filter that was set, for instance if the user tries to filter car brands only of a certain category I change the URL like 'cars?filter-brand[]=1'.
But when mutiple filters are applied I have no way of figuring out whether to load the data from the server or to load it from the history.
At the moment I am using the following code.
pushString variable is the new query string that will be created.
var back = [],forward = [];
if(back[back.length-1] === decodeURI(pushString)){ //check last back val against the next URL to be created
back.pop();
forward.push(currentLocation);
history.back();
return true;
}else if(forward[forward.length-1] === decodeURI(pushString)){
forward.pop();
back.push(currentLocation);
history.forward();
return true;
}else{
back.push(currentLocation); //add current win location
}
You can check if your filters are equivalent.
Comparing Objects
This is a simple function that takes two files, and lets you know if they're equivalent (note: not prototype safe for simplicity).
function objEqual(a, b) {
function toStr(o){
var keys = [], values = [];
for (k in o) {
keys.push(k);
values.push(o[k]);
}
keys.sort();
values.sort();
return JSON.stringify(keys)
+ JSON.stringify(values);
}
return toStr(a) === toStr(b);
}
demo
Using the URL
Pass the query part of the URL (window.location.search) to this function. It'll give you an object you can compare to another object using the above function.
function parseURL(url){
var obj = {}, parts = url.split("&");
for (var i=0, part; part = parts[i]; i++) {
var x = part.split("="), k = x[0], v = x[1];
obj[k] = v;
}
return obj;
}
Demo
History API Objects
You can store the objects with the History API.
window.history.pushState(someObject, "", "someURL")
You can get this object using history.state or in a popState handler.
Keeping Track of Things
If you pull out the toStr function from the first section, you can serialize the current filters. You can then store all of the states in an object, and all of the data associated.
When you're pushing a state, you can update your global cache object. This code should be in the handler for the AJAX response.
var key = toStr(parseUrl(location.search));
cache[key] = dataFromTheServer;
Then abstract your AJAX function to check the cache first.
function getFilterResults(filters, callback) {
var cached = cache[toStr(filters)]
if (cached != null) callback(cached);
else doSomeAJAXStuff().then(callback);
}
You can also use localstorage for more persistent caching, however this would require more advanced code, and expiring data.

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.