Node.js 开发web server博客项目[6]

Mac 终端 oh-my-zsh 配置
https://www.jianshu.com/p/64344229778a

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

6-3 cookie用于登录验证

1.

blog-node
——app.js

  // 解析 query
  // ...
  // 解析 cookie
  req.cookie = {}
  const cookieStr = req.headers.cookie || ''
  cookieStr.split(';').forEach(item => {
    if(!item) {
      return
    }
    const arr = item.split('=');
    // 拼接 Cookie 会自动增加空格,用 trim 方法去掉
    const key = arr[0].trim();
    const val = arr[1].trim();
    req.cookie[key] = val;
  })
  // console.log('req.cookies is...', req.cookie);

2.登录验证的测试

如果 cookie 里面有 username,已登录

blog-node
——src
————router
——————user.js

  // 登录
  // ...
  
  // 登录验证测试
  if (method === 'GET' && req.path === '/api/user/login-test') {
    if (req.cookie.username) {
      return Promise.resolve(
        new SuccessModel({
          username: req.cookie.username 
        })
      );
    } else {
      return Promise.resolve(new ErrorModel('尚未登录'));
    }
  }

3.登录临时改为 GET,参数从 query 里面取

演示在后端修改 Cookie

blog-node
——src
————router
——————user.js

  // 登录
  if(method === 'GET' && req.path === '/api/user/login') {
    // const { username, password } = req.body;
    const { username, password } = req.query;
    const result = login(username, password);
    return result.then(data => {
      if (data.username) {
        
        // 操作 Cookie
        res.setHeader('Set-Cookie', `username=${data.username}; path=/`);

        return new SuccessModel();
      } else {
        return new ErrorModel('登录失败');
      }
    });
  }

6-4&6-5 cookie做限制

登录成功后,用户可以通过设置 cookie, 任意伪造其他用户

1.限制前端修改 Cookie-httpOnly

// 操作 Cookie
res.setHeader('Set-Cookie', `username=${data.username}; path=/; httpOnly`);

2.设置Cookie 过期时间

blog-node
——src
————router
——————user.js

// 获取 cookie 的过期时间
const getCookieExpires = () => {
  const d = new Date();
  d.setTime(d.getTime() + (24 * 60 * 60 * 1000));
  console.log('d.toGMTString() is ', d.toGMTString());
  return d.toGMTString();
};
const handleUserRouter = (req, res) => {
  // ...

  // 操作 Cookie
  res.setHeader('Set-Cookie', `username=${data.username}; path=/; httpOnly; expires=${getCookieExpires()}`);

  // ...
};

6-6 session介绍

cookie => userid

const SESSTION_DATA = {}
const getPostData = (req) => {...}
// ...
  // 解析 session
  let needSetCookie = false
  let userId = req.cookie.userid
  if (userId) {
    if(!SESSION_DATA[userId]) {
      SESSION_DATA[userId] = {}
    }
  } else {
    needSetCookie = true
    userId = `${Date.now()}_${Math.random()}`
    SESSION_DATA[userId] = {}
  }
  req.session = SESSION_DATA[userId]
  getPostData(req).then(postData => {...}
    const blogResult = handleBlogRouter(req, res)
    if (blogResult) {

      if (needSetCookie) {
        res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}}`)
      }

      blogResult.then(blogData => {
        res.end(JSON.stringify(blogData))
      })
      return
    }
    const userResult = handleUserRouter(req, res)
    if (userResult) {

      if (needSetCookie) {
        res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}}`)
      }

      userResult.then(userData => {
        res.end(JSON.stringify(userData))
      })
      return
    }
  if (req.method === 'GET' && req.path === '/api/user/login') {
    // ...
    return result.then(data => {
      if (data.username) {

        req.session.username = data.username
        req.session.realname = data.realname
        console.log('req.session is...', req.session)

        //...
      } else {
        //...
      }
    })
  }
  if (req.method === 'GET' && req.path === '/api/user/login-test') {
    if (req.session.username) {
      return Promise.resolve(
        new SuccessModel({
          username: req.session
        })
      )
    } else {
      //...
    }
  }


6-8 从 session 到 redis

理论

6-9 redis 介绍

https://www.runoob.com/redis/redis-install.html

brew install redis

启动两个 terminal,运行:

  • redis-server
  • redis-cli
- keys *
- get 1574645202751_0.571581082859681
- del 1574645202751_0.571581082859681

6-11 nodejs 连接 redis

npm i redis --save

let REDIS_CONF
//...
  REDIS_CONF = {
    port: 6379,
    host: '127.0.0.1'
  }
const redis = require('redis')
const { REDIS_CONF } = require('../conf/db.js')

// 创建客户端
const redisClient = redis.createClient(REDIS_CONF.port, REDIS_CONF.host)
redisClient.on('error', err => {
    console.error(err)
})

function set(key, val) {
    if (typeof val === 'object') {
        val = JSON.stringify(val)
    }
    redisClient.set(key, val, redis.print)
}

function get(key) {
    const promise = new Promise((resolve, reject) => {
        redisClient.get(key, (err, val) => {
            if (err) {
                reject(err)
                return
            }
            if (val == null) {
                resolve(null)
                return
            }

            try {
                resolve(
                    JSON.parse(val)
                )
            } catch (ex) {
                resolve(val)
            }
        })
    })
    return promise
}
module.exports = {
  set,
  get
}

app.js

  • 注释掉之前处理 session 逻辑
// const SESSION_DATA = {}
  // let needSetCookie = false
  // let userId = req.cookie.userid
  // if (!userId) {
  //   needSetCookie = true
  //   userId = `${Date.now()}_${Math.random()}`
  //   SESSION_DATA[userId] = {}
  // } else {
  //   if (!SESSION_DATA[userId]) {
  //     SESSION_DATA[userId] = {}
  //   }
  // }
  // req.session = SESSION_DATA[userId]
const { get, set } = require('./src/db/redis')
//...
  // 解析 session (使用 redis)
  let needSetCookie = false
  let userId = req.cookie.userid
  if (!userId) {
    needSetCookie = true
    userId = `${Date.now()}_${Math.random()}`
    // 初始化 redis 中的 session 值
    set(userId, {})
  } 
  // 获取 session
  req.sessionId = userId
  get(req.sessionId).then(sessionData => {
    if (sessionData == null) {
      // 初始化 redis 中的 session 值
      set(req.sessionId, {})
      // 设置 session
      req.session = {}
    } else {
      req.session = sessionData
    }
    console.log('req.session ', req.session)
    return getPostData(req)
  })

router
——user.js

const { set } = require('../db/redis')
//...

set(req.sessionId, req.session)
  if (req.method === 'GET' && req.path === '/api/user/login-test') {
    if (req.session.username) {
      return Promise.resolve(
        new SuccessModel({
          session: req.session
        })
      )
    } else {
      return Promise.resolve(
        new ErrorModel('尚未登录')
      )
    }
  }

blog.js

// 统一的登录验证函数
const loginCheck = (req) => {
  if (!req.session.username) {
    return Promise.resolve(
      new ErrorModel('尚未登录')
    )
  } 
}
//...
const loginCheckResult = loginCheck(req)
if (loginCheckResult) {
  return loginCheckResult
}
// 哪里需要登录信息
req.session.username

6-15 nginx 反向代理

brew install nginx

nano /usr/local/etc/nginx/nginx.conf

3>worker_processes  4;
36>
server {
        listen       8080;
#        location / {
#            root   html;
#            index  index.html index.htm;
#        }

        location / {
            proxy_pass http://localhost:3000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
        }

        location /api/ {
            proxy_pass http://localhost:8000;
            proxy_set_header Host $host;
        }
}

nginx -t 【测试】

nginx 【启动】

nginx -s stop 【停止】

  if (req.method === 'GET' && req.path === '/api/blog/list') {
    let author = req.query.author
    const keyword = req.query.keyword
    // 管理员界面限制
    if (req.query.isadmin) {
      const loginCheckResult = loginCheck(req)
      if (loginCheckResult) {
        return loginCheckResult
      }
      author = req.session.username
    }

    const result = getList(author, keyword)
    return result.then(data => {
      return new SuccessModel(data)
    })
  }

注意:对象的转换

function set(key, val) {
    if (typeof val === 'object') {
        val = JSON.stringify(val)
    }
    redisClient.set(key, val, redis.print)
}

注意:userId 是保存在 request 里的

req.sessionId = userId

你可能感兴趣的:(Node.js 开发web server博客项目[6])