# express-session

> 1.5.0后的版本不再需要`cookie-parser`的支持了；并且session只是单纯的发送一个session ID 给客户端，而真正的session数据是存储在服务端的。并且默认情况下session是保存在内存当中的仅仅适用于开发和调试模式，至于生产模式下可能会导致内存泄露，得想个办法把它存数据库里或者文件中。

由于我数据库使用的是`mysql`，因此可以使用对应的mysql将session持久化存起来

> [connect-mssql](https://www.npmjs.com/package/connect-mssql) A SQL Server-based session store.

## 1.初始化session

* `name`参数设置客户端中cookie的key名称
* `secret`对session ID进行加盐的字符
* `resave`多个客户端并发请求时，保留最后一次请求并且覆盖前面的
* `saveUninitialized`初始化的session是否进行保存
* `maxAge`和`cookie.expires`参数都可以设置cookie过期时间，如果都设置了以最后设置的为准，还是设置`maxAge`好一些，以秒为单位
* `cookie.path`设置cookie存储的路径，默认是根域名下；当然可以修改为子域名
* `cookie.secure`只适用于https请求，设置为true时，在http请求下cookie失效

> 我设置只在/login API下才能够得到cookie，而在/people API下得不到；
>
> rolling: true, //每个请求都重新设置一个cookie ；当客户端手动删除cookie时，非常有用，我在这折腾了好久

```javascript
var session = require('express-session') //use session
app.use(
  session({
    secret: 'cotton',
    name: 'token',
    resave: false,
    saveUninitialized: true,
    cookie:{
        maxAge:86400000,  //设置cookie过期时间以毫秒为单位
        path:'/login'
    },
      rolling: true, //每个请求都重新设置一个cookie
  })
)
```

> rolling: true; 这个参数设置为真时，当用户手动清空掉cookie时，服务端仍旧会重新发送一份cookie；如果不设置的话，客户端是得不到cookie，进而服务端会出错；这里我弄了好久

## 2.将用户登录信息保存在session中

首先根据客户端cookie中的信息判断客户端对应的session中是否包含`login`字段；如果包含则无需进行数据库query；直接从session中获取用户信息；否则验证用户身份，并将用户信息存在session中。

```javascript
router.get('/login', function (req, res, next) {
  if (req.session.login) {
    res.send('ok')
  } else {
    req.session.login = true
    res.send('no')
  }
})
```

## 3.将session保存在文件中持久化

由于express-session将session信息保存在内存当中，因此为了防止node内心泄露，需要对session数据持久化

> 参考 <https://www.npmjs.com/package/session-file-store>

```javascript
var session = require('express-session') //use session
var FileStore = require('session-file-store')(session) //use file store session
var fileStoreOptions = {
  ttl: 86400,  //设置session文件过期时间，以秒为单位
  path: path.join(__dirname, './sessions'), //设置session保存路径
}
```

### 4.存信息的时候统一存进一个date对象内

当客户端第一次访问时，判断session是否存在`data`属性，如果不存在则进行进行身份验证，验证通过后修改session中data字段数据，并且返回成功代码给客户端；

如果失败则返回错误代码给客户端，进行重新登录

```javascript
router.get('/login', function (req, res, next) {
  if (req.session.data) {
    res.send(req.session.data) //处于登录状态了
  } else {
    req.session.data = true
    res.send('no') //非登录状态，进行数据库查询操作
  }
})
```

之后需要登录才能得到信息的接口，就直接判断当前session中是否存在数据，不存在就直接返回401，让前端进行登录才能获取到数据

## 登录验证API

当用户提交了账号和密码之后，进行验证；如果验证通过则将信息存储在session文件中，cookie中保留session文件ID

```javascript
const username = 'zpliu'
const password = '111'
router.post('/login', function (req, res, next) {
  if (req.session.data) {
    res.json(req.session.data)
    //处于登录状态了
  } else {
    //进行密码验证
    if (req.body.username === username && req.body.password === password) {
      req.session.data = {
        name: 'zpliu',
        grade: 'master',
        role: 'Administrator',
      }
      console.log(req.session)
      res.redirect('/login')  //这里重定向还是会产生一点问题，第一次登录会有404
    } else {
      res.send({
        code: 6000,
        message: '账号或密码错误',
      })
    }
  }
})
```

最终代码，已经加上了sql进行账号和密码的验证，以及MD5加密操作

> <https://github.com/zpliu1126/nodeAPI/blob/cfd3201f9b02a8d963a89ea8f5961c03997d3089/API/auth/index.js>

## 参考

1. <https://www.cnblogs.com/tugenhua0707/p/9098132.html>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://zpliu.gitbook.io/booknote/node/bao-cun-yong-hu-de-session.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
