HTTP itself is stateless - you may recall that we compare a web application to a conversation between two agents with very poor memory. This presents a problem if we want to implement a "login" functionality - the server needs to be able to remember that someone has already authenticated in an earlier request!
Like other web frameworks, UserFrosting uses PHP sessions to solve this problem. When a user visits your site, PHP will place a random, hard-to-guess string called the session id in the the Set-Cookie
header of the response. This is automatically stored by the user's browser in a cookie. It uniquely identifies the user and cannot easily be guessed by anyone without access to the user's browser.
The next time a user makes a request on your site (for example, visiting a page), your browser automatically sends the session id back to the server in the Cookie
request header. By sending the session id to the server with each subsequent request, the server can resume the user's session that was saved after the last request. You can think of the session id as a temporary "password" that your browser automatically sends to the server with each request.
The session itself is nothing more than an associative array, which PHP stores in a file or other persistence mechanism, like the database or a high-performance cache.
To actually associate a user's PHP session with their user account in the database, UserFrosting stores the user's user_id
in their session after they authenticate. This is stored in the account.current_user_id
key of the session.
UserFrosting uses this stored user_id
to retrieve the current user's complete account information when it is needed - for example, to determine the user's permissions or display personalized information to the user. Since the session is only stored on the server side, and users do not have direct access to read or modify their sessions, this prevents one user from impersonating another user (for example, the root user).
Users may not have direct access to their session, but your server-side code can access the current user's session via the session
service.
It is preferred to use the
session
service over PHP's$_SESSION
superglobal.
We can access session data using array dot notation:
$session = $this->ci->session;
echo $session['account.current_user_id'];
You can store additional data in the session simply by using the assignment operator:
$this->ci->session['secret.api.key'] = $customerApiKey;
You can determine if a particular session key exists using the has
method:
$session = $this->ci->session;
if ($session->has('secret.api.key')) {
...
}
Sometimes you will want to regenerate the session id, for example to prevent session fixation attacks. To do this, use the regenerateId
method:
$session = $this->ci->session;
$session->regenerateId();
If you pass a value of true
to this method, it will delete the old session record before creating the new session. Internally, this is just a wrapper for session_regenerate_id
. UserFrosting uses regenerateId(true)
when logging a user in.
To completely destroy the current session and its data, use the destroy
method:
$session = $this->ci->session;
$session->destroy();
UserFrosting uses this method to destroy the session when a user logs out.
If you pass a value of true
to this method, UserFrosting will set the expiration time for the current session cookie to a negative value, causing the browser to immediately delete the session cookie on the next request.
You should avoid storing additional information in the user's session whenever possible. Sessions are difficult to scale and can cause concurrency issues when they are used excessively. You should instead store additional persistent data in the database, cache or another more robust storage mechanism, and associate it with the user's
user_id
.
By default, UserFrosting stores sessions in individual files in app/sessions
. The associative arrays are encoded using PHP's serialization format.
If you'd prefer, UserFrosting can store your sessions in the database instead. To use this option, the sessions
table must exist in your database. This should have been created automatically for you in the built-in migrations.
To start using database sessions instead, set the value of session.handler
to database
in your configuration file. With this option, the serialized session data will be encoded in a base-64 string.