Nodefony Sessions

SESSIONS

Sevcice Sessions manage sessions of HTTP or WEBSOCKET requests.

  • Storages ( )
  • Use Sessions
  • Advanced Use

Session Configrations

Bundle App configurations file Location : app/config/config.js


  session: {
    start: false, // false || true || Session Context Name (waf)
    name: "nodefony",
    handler: "orm", // files | orm | memcached
    //save_path: "./tmp/sessions", // for session.storage.files only
    use_strict_mode: true,
    gc_probability: 1,
    gc_divisor: 100,
    gc_maxlifetime: 1440,
    use_cookies: true,
    use_only_cookies: true,
    referer_check: false,
    cookie: {
      maxAge: 0, // like cookie_lifetime php  => secondes or ms style ('1d', "1h")
      secure: false, // Set true for https site only see https://developer.mozilla.org/fr/docs/Web/HTTP/Headers/Set-Cookie
      httpOnly: true
    },
    memcached: {
      servers: {
        nodefony: {
          location: "127.0.0.1",
          port: 11211,
          weight: 1
        }
      }
    }
  }

Session Auto Start

Nodefony framework can configure autostart session in App bundle configuration file app/config/config.js



session: {
  start: true, // false || true || Session Context Name (waf)
}

Session Context Name , Web Application Firewall (WAF) can use context session name to manage strategy betwin secures areas



session: {
  start: "oauth", // false || true || Session Context Name (waf)
}

Start session in controller

 // don't use autostarter session

session: {
  start: false
}

Session must be started in Constructor of Controller called by front controller

module.exports = class usersController extends nodefony.controller {

  constructor(container, context) {
    super(container, context);

    // start session startSession(context)
    this.startSession(/*"oauth"*/);
  }

  /**
   *    @Method ({"GET", "POST"})
   *    @Route ( "/create", name="route-create")
   *
   */
  createAction() {
    console.log(this.session)
  }
}
Session {
  protoService: [Function: protoService],
  protoParameters: [Function: protoParameters],
  id:
   '008d8494242229256948b50ff7e64d98e71adcb6d5b6de622cff057298da2b62c45c95c5929d9a5c',
  scope: {},
  services: protoService {},
  parameters: protoParameters {},
  status: 'active',
  manager:
   sessions {
     name: 'SESSIONS',
     options: [Object],
     container: [Container],
     kernel: [appKernel],
     syslog: [Syslog],
     settingsSyslog: [Object],
     notificationsCenter: [Notification],
     httpKernel: [httpKernel],
     sessionStrategy: 'migrate',
     settings: [Object],
     proba: 1,
     divisor: 100,
     defaultSessionName: 'nodefony',
     sessionAutoStart: null,
     storage: [dbSessionStorage] },
  strategy: 'migrate',
  strategyNone: false,
  logger: [Function: bound logger],
  name: 'nodefony',
  settings:
   { start: false,
     use_strict_mode: true,
     name: 'nodefony',
     handler: 'orm',
     save_path: '/tmp/sessions',
     gc_probability: 1,
     gc_divisor: 100,
     gc_maxlifetime: 1440,
     hash_function: 'md5',
     use_cookies: true,
     use_only_cookies: true,
     referer_check: false,
     cookie: [Object],
     memcached: [Object] },
  storage:
   dbSessionStorage {
     manager: [sessions],
     orm: [sequelize],
     gc_maxlifetime: 1440,
     contextSessions: [],
     entity: session },
  context:
   httpContext {
     name: 'HTTP2 CONTEXT',
     options: [Object],
     container: [Scope],
     kernel: [appKernel],
     syslog: [Syslog],
     settingsSyslog: [Object],
     notificationsCenter: [Notification],
     type: 'HTTP2',
     kernelHttp: [httpKernel],
     router: [router],
     translation: [Translation],
     resolver: [Resolver],
     nbCallController: 0,
     requestEnded: true,
     session: [Circular],
     sessionService: [sessions],
     sessionAutoStart: 'default',
     csrfService: [csrf],
     cookies: [Object],
     crossDomain: null,
     secureArea: null,
     security: null,
     metaSecurity: [Object],
     user: [User],
     token: [userPasswordToken],
     secure: false,
     isJson: false,
     waitAsync: false,
     profiler: false,
     accessControl: [],
     isControlledAccess: false,
     uploadService: [upload],
     requestSettings: [Object],
     queryStringParser: [Object],
     isElectron: false,
     protocol: '2.0',
     scheme: 'https',
     pushAllowed: true,
     request: [http2Request],
     response: [http2Response],
     csrf: null,
     cookieSession: [Cookie],
     method: 'GET',
     isAjax: false,
     isHtml: true,
     isRedirect: false,
     sended: false,
     showDebugBar: true,
     timeoutExpired: false,
     promise: null,
     timeoutid: null,
     profiling: [Object],
     url: 'https://localhost:5152/',
     port: '5152',
     originUrl: [Url],
     domain: 'localhost',
     validDomain: true,
     remoteAddress: '127.0.0.1',
     proxy: null,
     locale: 'en_en' },
  contextSession: 'default',
  lifetime: 0,
  saved: false,
  flashBag: {},
  applyTranId: 0,
  cookieSession:
   Cookie {
     settings: [Object],
     name: 'nodefony',
     signed: false,
     value:
      '008d8494242229256948b50ff7e64d98e71adcb6d5b6de622cff057298da2b62c45c95c5929d9a5c',
     originalMaxAge: 0,
     maxAge: 0,
     expires: null,
     path: '/',
     domain: null,
     httpOnly: true,
     secure: false,
     sameSite: null
  }
}

Use session

Session Attributes

Getter // Setter

 // Getter // Setter
  createAction() {

    let foo = this.session.get("foo")
    if (! foo){
      foo = this.session.set("foo", {bar:true})
    }

  }

  // getAttributtes
  createAction() {
    let attributes = this.session.getAttributtes();
    console.log(attributes)
    {
      foo: { bar: true }
    }
  }

Session Metas

Meta attributes are needed for internal use but may be useful for better managing session usage.

module.exports = class myController extends nodefony.controller {

  constructor(container, context) {
    super(container, context);
    this.startSession();
  }

  // Example getMetaBag / setMetaBag

  createAction() {

    let kernelMeta = this.session.getMetaBag("kernel");
    if (!kernelMeta.domain) {
      this.session.setMetaBag("kernel.domain", this.kernel.domain);
    }

  }

  // invalide session after 1 minute
  checkSession() {
    let lastUsed = this.session.getMetaBag("lastUsed");
    lastUsed = new Date(lastUsed).getTime();
    let now = new Date().getTime();
    if ( ( now - lastUsed ) > 60000) {
      this.session.invalidate();
      return false ;
    }
    return true;
  }

  createAction() {
      this.checkSession();
      ...
  }
}

let metas = this.session.getMetas();
console.log(metas)

protoParameters {
  lifetime: 0,
  context: 'default',
  request: 'HTTP2',
  created: '2019-04-10T19:15:32.980Z',
  remoteAddress: '127.0.0.1',
  host: 'localhost:5152',
  user_agent:
   'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',
  url:
   Url {
     protocol: 'https:',
     slashes: true,
     auth: null,
     host: 'localhost:5152',
     port: '5152',
     hostname: 'localhost',
     hash: null,
     search: null,
     query: null,
     pathname: '/test/unit/session/get/attributes',
     path: '/test/unit/session/get/attributes',
     href: 'https://localhost:5152/test/unit/session/get/attributes' },
  lastUsed: '2019-04-10T19:21:10.477Z',
  kernel: { domain: '0.0.0.0' }
}

Session FlashBag

Session FlashBag are useful for time-limited use (stealth)

module.exports = class myController extends nodefony.controller {

  constructor(container, context) {
    super(container, context);
    this.startSession();
  }

  // Example setFlashBag

  createAction() {
    this.session.setFlashBag("info", "My log info" )
    return this.render("app::index.hml.twig");
  }

}

Usage in twig getFlashBag

{% extends './base.html.twig' %}

{% set error = getFlashBag("error") %}
{% set info = getFlashBag("info") %}

{% if info %}
  <div class="alert alert-primary alert-dismissible fade show  mt-2" role="alert">
    <strong>INFO :</strong>
    {{info|escape}}
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
      <span aria-hidden="true">×</span>
    </button>
  </div>
{% endif %}
{% if error %}
  <div class="alert alert-danger alert-dismissible mt-2" role="alert">
    <strong>ERROR :</strong>
    {{error|escape}}
    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
      <span aria-hidden="true">×</span>
    </button>
  </div>
{% endif %}