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