<!--toc-->
|
|
## General
|
|
In this tutoring we would show the basics of using sessions in CppCMS --- how to store connection persistent data in stateless HTTP protocol.
|
|
## Code
|
|
Our current code would be based on [start with forms](/wikipp/en/page/cppcms_1x_forms) code.
|
|
### Templates and Content
|
|
In this example we would save the information about user using `session_interface` object that can be accessed by `session()` member function of `cppcms::application`.
|
|
This information would be displayed to the user every time one visits the page.
|
|
First of all let's change our "content.h": Instead of showing person's sex and state we should display a prefix "Mr", "Miss" or "Mrs" according to our saved parameters.
|
|
So lets change line:
|
|
std::string name,state,sex;
|
|
to
|
|
std::string name,who;
|
|
And we would use following template:
|
|
<h1>Hello <%= who %> <%= name %></h1>
|
<% if (content.age != -1.0) %>
|
<p>Your age is <%= age %></p>
|
<h2>Change details</h2>
|
<% else %>
|
<h2>Input your details</h2>
|
<% end %>
|
<form method="post" action="" >
|
<% form as_p info %>
|
|
__Notes:__ We can inject arbitrary C++ code into conditions between two brackets `()` (line 2). However, now we should refer to all content class variables using `content` member. Templates engine would not substitute correct prefix for you, because it is native C++ code.
|
|
### Saving data
|
|
Now let's rewrite out `hello::main` function:
|
|
First of all let's load new data from the form when it submitted to session object, instead of content. This information is preserved withing different requests:
|
|
|
content::message c;
|
if(request().request_method()=="POST") {
|
c.info.load(context());
|
if(c.info.validate()) {
|
session()["name"]=c.info.name.value();
|
session()["sex"]=c.info.sex.selected_id();
|
session()["state"]=c.info.martial.selected_id();
|
session().set("age",c.info.age.value());
|
c.info.clear();
|
}
|
}
|
|
|
__Notes:__
|
|
- Note on operator `[]` of session object:
|
|
string &session_interface::operator[](string const &)
|
|
It's semantics similar to semantics of `std::map`'s `[]` operator. Accessing it's member returns the reference to the string by the key. If key not exists, it is created.
|
|
- The storage object is std::string. In order to store other different values, you should do lexical cast to string. The simplest way is to use template member function
|
|
template<typename T>
|
void set(string const &key,T const &value);
|
|
Now, our session data would be preserved between requests and we can fetch it:
|
|
### Fetching Data
|
|
if(session().is_set("name")) {
|
c.name=session()["name"];
|
if(session()["sex"]=="m") {
|
c.who="Mr";
|
}
|
else {
|
if(session()["state"]=="s") {
|
c.who="Miss";
|
}
|
else {
|
c.who="Mrs";
|
}
|
}
|
c.age=session().get<double>("age");
|
}
|
else {
|
c.name="Visitor";
|
c.age=-1;
|
}
|
render("message",c);
|
|
|
__Notes:__
|
|
- First time, you ask for any field, you should check if it is exists:
|
|
if(session().is_set("name")) {
|
|
It would be incorrect to write:
|
|
if(!session()["name"].empty()) {
|
|
Because you would change session object and set the
|
value of "name" to empty string, and this value would
|
be saved. This is probably not what you want.
|
|
Then, if you always set all fields together, it is safe
|
to fetch them directly. CppCMS sessions guarantees
|
consistency of the data.
|
|
- You can fetch non-string values using template member function:
|
|
template<typename T>
|
T get(std::string const &key)
|
|
- `get` and `set` template member functions use C++ `std::istream` and `std::ostream` to convert the data between the textual representation and its value.
|
So you can use any type T that is writable to and readable
|
from C++ I/O streams.
|
|
## Configuration --- behind the scenes
|
|
### Storage Backend
|
|
CppCMS has several options to session management. In every case cookies are used --- there is no "GET" or "POST" methods for storing session information like `/page/?sid=2e7f60c43b88d4b554a`.
|
|
The developer has several options to save information:
|
|
- Store all data at client side in signed and optionally encrypted cookies
|
- Store all data at server size and use session id to retrieve the information each time
|
- Store all data at server side and use session id to retrieve the information each time
|
- Use combination of them: If amount of data too big to be
|
stored in cookies, it would be stored on server side.
|
|
We would add following lines to our CppCMS configuration file:
|
|
"session" : {
|
"expire" : "renew",
|
"timeout" : 604800,
|
"location" : "client",
|
"client" : {
|
"hmac" : "sha1",
|
"hmac_key" : "3891bbf7f845fd4277008a63d72640fc13bb9a31"
|
}
|
}
|
|
__Notes:__
|
|
- Defining `session.location`, would enable session interface. Most suitable option for 99% of cases is to store the data in signed and encrypted cookies on client side.
|
- When using client side storage the signature method (hmac) and a suitable private key should be provided.
|
|
Optionally an encryption can be added by setting
|
`session.client.cbc` method like aes and providing
|
a private key.
|
|
You should keep the private key unique per application and never disclose it. You may generate such key easily using `cppcms_make_key` utility that uses [`/dev/random`](http://en.wikipedia.org/wiki/Urandom) interface.
|
|
### Duration Options
|
|
You can define several session duration options:
|
|
- Browser based, until window is closed --- "browser" -- the default one.
|
- Time based with renewal --- "renew"
|
- Time based with hard limit after first time creation --- "fixed". It is useful when you want to force user to login every predefined period of time.
|
|
Each type of expiration has its time limit (even browser one has its limit). It can be defined using `session.timeout` parameter. The default one is 24 hours.
|
|
For example:
|
|
"expire" : "renew",
|
"timeout" : 604800,
|
|
|
## Security Considerations
|
|
The full tutorial about sessions and security can
|
be found here:
|
|
- [Secure Programming: Sessions](/wikipp/en/page/secure_programming#Sessions)
|
|
Make sure you read it and understand it.
|
|
Rules of thumb:
|
|
- Don't store valuable data in the session, it is ok to store user identification or preferences but it is not
|
good idea to store user's rights.
|
- If you use client side storage be aware of replay-attacks - where user can restore his cookie to previous state.
|
- Call `session().reset_session()` after critical operations like authentication in order to prevent session-fixation attacks.
|
|
---
|
|
← [Working With Forms][prev]
|
| [Top](#maincontent)
|
| [Basic Caching][next] →
|
|
[prev]: /wikipp/en/page/cppcms_1x_forms
|
[next]: /wikipp/en/page/cppcms_1x_basic_caching |