Node.js 从零开发 web server博客项目[登录]
web server博客项目
- Node.js 从零开发 web server博客项目[项目介绍]
- Node.js 从零开发 web server博客项目[接口]
- Node.js 从零开发 web server博客项目[数据存储]
- Node.js 从零开发 web server博客项目[登录]
- Node.js 从零开发 web server博客项目[日志]
- Node.js 从零开发 web server博客项目[安全]
- Node.js 从零开发 web server博客项目[express重构博客项目]
- Node.js 从零开发 web server博客项目[koa2重构博客项目]
- Node.js 从零开发 web server博客项目[上线与配置]
文章目录
cookie
什么是 cookie
- 存储在浏览器的一段字符串 ( 最大5kb )
- 跨域不共享
- 格式如 k1=v1; k2=v2; k3=v3; 因此可以存储结构化数据
- 每次发送 http 请求 , 会将请求域的 cookie 一起发送给 server
- server 可以修改 cookie 并返回给浏览器
- 浏览器中也可以通过 JavaScript 修改 cookie ( 有限制 )
JavaScript 操作 cookie , 浏览器中查看 cookie
客户端查看 cookie , 三种方式
- Network ->Reques Headers ->Cookie
- Application -> Cookie
document.cookie
JavaScript 查看\修改 cookie ( 有限制 )
document.cookie = 'foo=bar;'只能增加 cookie, 不能删除
server 端操作 cookie , 实现登录验证
app.js
// 解析 cookie
req.cookie = {}
const cookieStr = req.headers.cookie || '' // k1=v1; k2=v2; k3=v3
cookieStr.split(';').forEach(item => {
if (!item) {
return
}
const arr = item.split('=')
const key = arr[0]
const val = arr[1]
req.cookie[key] = val
})
console.log('req.cookie is: ', req.cookie)
// 在客户端中 document.cookie = 'username: zhangsan;'
// req.cookie is: { username: 'zhangsan' }
router/user.js
// 登录
if (method === 'GET' && path === '/api/user/login') {
// const {
// username,
// password
// } = req.body
const { username, password } = req.query
const result = login(username, password)
// if (result) {
// return new SuccessModel(result)
// } else {
// return new ErrorModel('登录失败')
// }
return result.then(data => {
if (data.username) {
// 操作 cookie
res.setHeader('Set-Cookie', `username=${data.username}; path=/`)
return new SuccessModel()
}
return new ErrorModel('登录失败')
})
}
// 登录验证测试
if (method === 'GET' && req.path === '/api/user/login-test') {
if (req.cookie.username) {
return Promise.resolve(
new SuccessModel({
username: req.cookie.username
})
)
}
return Promise.reject(
new ErrorModel('登录失败')
)
}
cookie做限制
在客户端当你登录成功后 ( username=lisi ) -> 删除 cookie ( username=lisi ) -> 添加 cookie ( username=zhangsan ) 会发现 用张三的账号操作的李四账号
router/user.js
const {
login
} = require('../controller/user')
const { SuccessModel, ErrorModel } = require('../model/resModel')
// 获取 cookie 的过期时间
const getCookieExpires = () => {
const d = new Date()
d.setTime(d.getTime() + (24 * 60 * 60 * 1000))
return d.toGMTString() // Mon, 08 Jul 2019 05:27:33 GMT
}
handleUserRouter = (req, res) => {
const {
method,
path
} = req
// 登录
if (method === 'GET' && path === '/api/user/login') {
// const {
// username,
// password
// } = req.body
const { username, password } = req.query
const result = login(username, password)
// if (result) {
// return new SuccessModel(result)
// } else {
// return new ErrorModel('登录失败')
// }
return result.then(data => {
if (data.username) {
// 操作 cookie
res.setHeader('Set-Cookie', `username=${data.username}; path=/; httpOnly; expires=${getCookieExpires()}`)
// path=/ 所有网站都生效
// httpOnly 只允许前端更改
// expires 过期时间
return new SuccessModel()
}
return new ErrorModel('登录失败')
})
}
// 登录验证测试
if (method === 'GET' && req.path === '/api/user/login-test') {
if (req.cookie.username) {
return Promise.resolve(
new SuccessModel({
username: req.cookie.username
})
)
}
return Promise.reject(
new ErrorModel('登录失败')
)
}
}
module.exports = handleUserRouter
session
- 上一节的问题 : 会暴露 username , 很危险
- 如何解决 : cookie 中存储 userid , server 端对应 username
- 解决方案 : session , 即 sever 端存储用户信息
app.js
// session 数据
const SESSION_DATA = {}
// 获取 cookie 的过期时间
const getCookieExpires = () => {
const d = new Date()
d.setTime(d.getTime() + (24 * 60 * 60 * 1000))
return d.toGMTString() // Mon, 08 Jul 2019 05:27:33 GMT
}
...
// 解析 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]
...
// 处理 user 路由
const userResult = handleUserRouter(req, res)
if (userResult) {
userResult.then(userData => {
if (needSetCookie) {
res.setHeader('Set-Cookie', `userid=${userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
}
res.end(
JSON.stringify(userData)
)
})
return
}
router/user.js
return result.then(data => {
if (data.username) {
// 操作 cookie
res.setHeader('Set-Cookie', `userid=${data.userId}; path=/; httpOnly; expires=${getCookieExpires()}`)
// path=/ 所有网站都生效
// httpOnly 只允许前端更改
// expires 过期时间
// 设置 session
req.session.username = data.username
req.session.realname = data.realname
console.log('req.session is : ', req.session)
return new SuccessModel(req.session)
}
return new ErrorModel('登录失败')
})
}
// 登录验证测试
if (method === 'GET' && req.path === '/api/user/login-test') {
if (req.session.username) {
return Promise.resolve(
new SuccessModel({
username: req.session
})
)
}
return Promise.reject(
new ErrorModel('尚未登陆')
)
}
session 存入 redis
cnpm i redis -S- conf/db.js
const env = process.env.NODE_ENV // 环境参数
// 配置
let MYSQL_CONF
let REDIS_CONF
if (env === 'dev') {
// MySQL
MYSQL_CONF = {
host: 'localhost',
user: 'root',
password: 'root',
port: '3306',
database: 'myblog'
}
// redis
REDIS_CONF = {
port: 6379,
host: '127.0.0.1'
}
}
if (env === 'production') {
MYSQL_CONF = {
host: 'localhost',
user: 'root',
password: 'root',
port: '3306',
database: 'myblog'
}
// redis
REDIS_CONF = {
port: 6379,
host: '127.0.0.1'
}
}
module.exports = { MYSQL_CONF, REDIS_CONF }
- 创建
db/redis.js
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
}
- router/blogs.js
const {
getList,
getDetail,
newBlog,
updateBlog,
delBlog
} = require('../controller/blog')
const { SuccessModel, ErrorModel } = require('../model/resModel')
// 统一的登录验证函数
const loginCheck = (req) => {
if (!req.session.username) {
return Promise.resolve(
new ErrorModel('尚未登录')
)
}
}
const handleBlogRouter = (req, res) => {
const method = req.method // GET POST
const id = req.query.id
// 获取博客列表
if (method === 'GET' && req.path === '/api/blog/list') {
let author = req.query.author || ''
const keyword = req.query.keyword || ''
// const listData = getList(author, keyword)
// return new SuccessModel(listData)
if (req.query.isadmin) {
// 管理员界面
const loginCheckResult = loginCheck(req)
if (loginCheckResult) {
// 未登录
return loginCheckResult
}
// 强制查询自己的博客
author = req.session.username
}
const result = getList(author, keyword)
return result.then(listData => {
return new SuccessModel(listData)
})
}
// 获取博客详情
if (method === 'GET' && req.path === '/api/blog/detail') {
// const data = getDetail(id)
// return new SuccessModel(data)
const result = getDetail(id)
return result.then(data => {
return new SuccessModel(data)
})
}
// 新建一篇博客
if (method === 'POST' && req.path === '/api/blog/new') {
// const data = newBlog(req.body)
// return new SuccessModel(data)
const loginCheckResult = loginCheck(req)
if (loginCheckResult) {
// 未登录
return loginCheckResult
}
req.body.author = req.session.username
const result = newBlog(req.body)
return result.then(data => {
return new SuccessModel(data)
})
}
// 更新一篇博客
if (method === 'POST' && req.path === '/api/blog/update') {
const loginCheckResult = loginCheck(req)
if (loginCheckResult) {
// 未登录
return loginCheckResult
}
const result = updateBlog(id, req.body)
return result.then(val => {
if (val) {
return new SuccessModel()
} else {
return new ErrorModel('更新博客失败')
}
})
}
// 删除一篇博客
if (method === 'POST' && req.path === '/api/blog/del') {
const loginCheckResult = loginCheck(req)
if (loginCheckResult) {
// 未登录
return loginCheckResult
}
const author = req.session.username
const result = delBlog(id, author)
return result.then(val => {
if (val) {
return new SuccessModel()
} else {
return new ErrorModel('删除博客失败')
}
})
}
}
module.exports = handleBlogRouter
- router/user.js
const { login } = require('../controller/user')
const { SuccessModel, ErrorModel } = require('../model/resModel')
const { set } = require('../db/redis')
const handleUserRouter = (req, res) => {
const method = req.method // GET POST
// 登录
if (method === 'POST' && 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) {
// 设置 session
req.session.username = data.username
req.session.realname = data.realname
// 同步到 redis
// console.log(req.session)
set(req.sessionId, req.session)
return new SuccessModel()
}
return new ErrorModel('登录失败')
})
}
}
module.exports = handleUserRouter
和前端联调
- 登录功能依赖 cookie , 必须用浏览器来联调
- cookie 跨域不共享 , 前端和 server 端必须同域
- 需要用到 nginx 做代理 , 让前后端端同域
Node.js 从零开发 web server博客项目[登录]的更多相关文章
- Node.js 从零开发 web server博客项目[express重构博客项目]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[数据存储]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[koa2重构博客项目]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[安全]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[日志]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[接口]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Node.js 从零开发 web server博客项目[项目介绍]
web server博客项目 Node.js 从零开发 web server博客项目[项目介绍] Node.js 从零开发 web server博客项目[接口] Node.js 从零开发 web se ...
- Vue+node.js实现一个简洁的个人博客系统
本项目是一个用vue和node以及mysql实现的一个简单的个人博客系统,整体逻辑比较简单.但是可以我们完整的了解一个项目从数据库到后端到前端的实现过程,适合不太懂这一块的朋友们拿来练手. 本项目所用 ...
- github pages + Hexo + node.js 搭建属于自己的个人博客网站
之前我写过一篇用Github实现个人主页的博客:https://www.cnblogs.com/tu-0718/p/8081288.html 后来看到某个大佬写的文章:[5分钟 0元搭建个人独立 ...
随机推荐
- Android PopupWindow显示之后所在的Activity结束的时候出现短暂黑屏问题
在当前Activity弹出PopuoWindow后,点击取消弹窗,然后结束当前Activity时会出现短暂黑屏现象.这是由于设置背景透明度时候造成的. //设置添加屏幕的背景透明度 public vo ...
- 初学Linux (Linux_note)
根目录:/ /root: 存放root用户相关文件 /home: 存放不同用户的相关文件 /bin: 存放常用命令的目录 /sbin: 要具有一定权限才可以使用的命令 /mnt: 默认挂载光驱和软驱的 ...
- MongoDB最新4.2.7版本三分片集群修改IP实操演练
背景 重新组网,需要对现有MongoDB分片集群服务器的IP进行更改,因此也需要对MongoDB分片集群的IP也进行相应的更新,而MongoDB分片集群的IP修改不能单纯的通过配置来进行,需要一番折腾 ...
- docker 启动容器失败 id already in use
问题:id already in use 解决:/etc/docker/daemon.json {"shutdown-timeout": 60}
- php使用curl来获取远程图片
本文章来介绍php使用curl来获取远程图片实现方法,有需要了解采集远程图片的朋友不防进入参考. curl要求php环境支持才行. 可以运行phpinfo()函数是否支持,一般要将php.ini中;e ...
- ABP开发框架的技术点分析(1)
ABP是ASP.NET Boilerplate的简称,ABP是一个开源且文档友好的应用程序框架.ABP不仅仅是一个框架,它还提供了一个最徍实践的基于领域驱动设计(DDD)的体系结构模型.ABP框架可以 ...
- jieba分词-强大的Python 中文分词库
1. jieba的江湖地位 NLP(自然语言)领域现在可谓是群雄纷争,各种开源组件层出不穷,其中一支不可忽视的力量便是jieba分词,号称要做最好的 Python 中文分词组件. 很多人学习pytho ...
- oeasy教你玩转linux010104灵魂之问whatis
灵魂之问whatis 回忆上节课 我们上次在系统里面乱转
- Tesseract OCR 安装尝试
1.简介 Tesseract是一个图像识别项目,将图中的文字识别出来.将一个.jpg .png 等等 的图片作为输入,.txt作为识别内容输出 Tesseract项目GitHub地址 2.安装 你可以 ...
- Prometheus 与 国产 TDengine 的对比
通过对比,能加深对这两个系统的理解,方便后续架构选型时作出正确决定.他们的设计思路有很多值得借鉴的地方,虽然工作中需要用到这些知识的地方不多,但是了解他们的设计细节能极大满足我的好奇心. 1.场景和需 ...