登陆注册流程和token加密
有问题的知识点
-
// [ result.status == 1 && 'token' ]: result.status == 1 && token token: result.status == 1 && token || '用户名密码错误,token不返回'
- 操作数据库 mongoose
一.token 重点
-
什么是token?
- token是一段经过后端处理【 后端加密算法 】的特殊字符,后端在前端登录时,会给前端返回这个字符,前端拿到这个字符之后,要将它存入cookie,
-
token的作用是什么?
- 项目自动登录
- 身份验证
- 前端发送的每一个数据请求,要求携带一个token数据
- 权限验证
- 普通用户
- 会员用户
- 管理员
- 原理:
- 当用户注册并登录后,后端会给它返回一个token字符,
-
使用
- 软件安装教程
- 根目录创建了一个rsa文件夹: 用于存放公钥和私钥
- 私钥 -> 加密
- 公钥 -> 解密
-
生成token要用
- 安装 openssl 软件(后端软件)
- 引入第三方模块 jsonwebtoken (npm i jsonwebtoken -S ),使用方式见npm官网
- 通过软件,在终端里面输入以下命令,能生成 非对称加密 通过私钥产生token 通过公钥解密token
// 1.产生公钥和私钥 // 产生私钥 openssl genrsa -out ./private_key.pem 1024 1024 代表私钥长度 // 产生公钥 openssl rsa -in ./private_key.pem -pubout -out ./public_key.pem
二.登陆注册流程
- 创建项目
npm express -generator -g
npx express -e . (-e 表示项目使用ejs 模板, . 表示在当前目录创建项目)
该命令在npm 是5.2以上版本会 省略安装 npm express -generator -g
- 前端发ajax 请求,并判断cookie 有没有token,有cookie token存在自动登陆。否则要生成token字符
// 自动登录
function load () {
const token = cookieUtil.get('TOKEN')
if ( token ) {
setTimeout(function () {
location.href = "./index.html"
},2000)
}
}
//发请求,少些内容了
$.ajax({
url: 'http://localhost:3000/login',
data: {
username: $('#username').val(),
password: $('#password').val(),
token: cookieUtil.get( 'TOKEN' )
},
})
- epxress 脚手架 响应数据和打造接口
router.route(’/login’).post(( req,res,next )=>{} ) 这是配置路由的一种链式写法
router.post(’/login’,( req,res,next )=>{} ) 这是配置路由的另一种写法
req.body 是前端发送请求发送来的内容
res.render(‘login’,{ data: {})===== login第一个参数是渲染模板名字,第二个参数是发给前端的值
const router = express.Router()
router.route('/login')//配置路由
.post( async ( req,res,next )=>{})
// 进行数据库操作
const result = await users.query( req.body )
res.render('login',{//login 是渲染的模板ejs的名字,后缀名可省略
data: JSON.stringify({//data是返回给前端的内容
status: result.status,
info: result.info,
token: result.status == 1 && token || '用户名密码错误,token不返回'
})
})
- 解决跨域
npm i cor -S 在pp根组件
var cors = require('cors')
// 在使用中间件前面解决跨域
app.use(cors({
"origin": "*",
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
"preflightContinue": false,
"optionsSuccessStatus": 200
}))
- 数据库操作
* 什么是mongoose?
* 它就是一个用于操作MongoDB数据库的一个对象,是一个封装对象
* mongoose使用?
* 1. 引入mongoose
* 2. 连接数据库
* 3. 创建骨架【 定义字段 】
* 4. 创建模型 -> 用于操作数据库
* 5. 创建实体 -> 用于数据库增加操作
- token 生成和 路由文件配置路由
(token 是后端文件,所以前端html文件要放到服务器下)
打造接口,app.use(’/’,loginRouter) 使用中间件,在根目录使用,相当于和二级路由路径拼接
安装npm 第三方插件 jsonwebtoken
const private_key = fs.readFileSync( path.join( __dirname, ‘…/rsa/private_key.pem’))
username 是准备要加密的内容,通过jsonwebtoken来生成token字符
const token = jwt.sign( username,private_key,{ algorithm: ‘RS256’ } )
const { users } = require('../database')
// 打造login接口
const jwt = require('jsonwebtoken')
router.route('/login') // 打造了 http://localhost:3000/login
.post( async ( req,res,next ) => {
// 接收前端发来的数据 console.log('req.body',req.body)
// 如果前端的token是空的,那么我们需要返回给它新的token
// 如果有,那么自动登录
const { token,username } = req.body
if ( !token ) {
// 表示token是空的,我们要返回新的给它
// 生成token给它
// 1. 通过fs来读取私钥
const private_key = fs.readFileSync( path.join( __dirname, '../rsa/private_key.pem'))
// 2. 通过jsonwebtoken来生成token字符
// jwt.sign( 数据, 私钥, 加密算法配置 )
//username 是准备要加密的内容
const token = jwt.sign( username,private_key,{ algorithm: 'RS256' } )
// 进行数据库操作
const result = await users.query( req.body )
res.render('login',{
data: JSON.stringify({
status: result.status,
info: result.info,
// [ result.status == 1 && 'token' ]: result.status == 1 && token
token: result.status == 1 && token || '用户名密码错误,token不返回'
})
})
}
})
module.exports = router // 导出模块
三 .mongoose来操作MongoDB
mongoose使用?
* 1. 引入mongoose
* 3. 创建骨架【 定义字段 】
* 4. 创建模型 -> 用于操作数据库
* 5. 创建实体 -> 用于数据库增加操作
说明:
- 只有add(req.body)增加的时候采用实体 ,把请求的内容当参数传过来
- userModel.find({},( err,docs ) 查找数据库的所有,
- docs 就是数据库查到的结果,是一个数组 [{}]
- 存数据
- const userEnity = new userModel( req.body )
- userEnity.save( err => {})
// * 1. 引入mongoose
const mongoose = require('mongoose') // mongoose 就是一个实例,这个实例身上有很多的方法
// 2. 连接数据库
const DB_URL = `mongodb://${ HOST }:27017/${ DB_NAME }` //DB_NAME数据库名字
mongoose.connect( DB_URL, err => { // 错误优先的回调函数
// ! 错误优先指的是第一个参数是err/error
if ( err ) {
console.log( err )
} else {
// 连接成功
console.log('数据库连接成功')
}
})
//3. 创建骨架 Schema 【 定义字段 】 类似: 一个表就是一个骨架,所以骨架不止一个
const userSchema= new mongoose.Schema({
username: String,
password: String
})
//4. 创建模型 -> 用于操作数据库
// const useModel = mongoose.model( 集合名称【 复数 】,对应的骨架
const userModel = mongoose('users',userSchema)//users 是数据库集合的名字
//5. 创建实体,是增加的时候才创建 const userEnity = new userModel( data ) , userEnity.save(),存数据库
// * 6. 数据库操作 CURD
// 是对users集合的操作,操作的是userModel模型
// 增加 userModel.save()
// 删除 userModel.findById( _id, ( err,doc ) => { doc.remove() })
// 修改 userModel.findById( _id, ( err,doc ) => { doc.username = xxx doc.save() })
// 查询 user.find({},( err,docs ) => { })
四 .token的补充说明
JWT【 全称: JsonWebToken 】
-
用户登录 服务器端产生一个token (加密字符串) 发送给前端
-
前端将token 进行保存
-
前端发起数据请求的时候携带token
-
服务端 验证token 是否合法 如果合法继续操作 不合法终止操作
-
token 的使用场景 无状态请求 保持用户的登录状态 第三方登录(token+auth2.0)
非对称加密 通过私钥产生token 通过公钥解密token
// 1.产生公钥和私钥
// 产生私钥 openssl genrsa -out ./private_key.pem 1024 1024 代表私钥长度
// 产生公钥 openssl rsa -in ./private_key.pem -pubout -out ./public_key.pem
let private_key=fs.readFileSync(path.join(__dirname,'./private_key.pem'))
let public_key=fs.readFileSync(path.join(__dirname,'./public_key.pem'))
var token = jwt.sign(palyload, private_key,{ algorithm: 'RS256'});
console.log(token)
let token='eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IueUqOaIt2lkIiwiaWF0IjoxNTUxMTUyNzk1fQ.TI_xDBvObHGAH7EV40WWpQemm5nx077Gdjq-pzDx0NWN5YFd40S7XcLmgoDdYscLM7vMOP0c7z1l83JUixqk7IBjBCU-tMNo_G5_-LGkQjV3vDYq_3TkXTl42lgmFA-EBey7W6W1PgPfYlowyHAyp-07hXaMRevgVkXm2lPEFXo'
var decoded = jwt.verify(token, public_key);
五. 数据库的增删改查
/*
* 此文件是对users集合的操作
*/
const { userSchema } = require('../schema')
const model = require('../model')
const userModel = model('users',userSchema)
const users = {
add ( data ) {
// 我现在要将add方法的处理结果返到add函数外面
return new Promise(( resolved,rejected ) => {
// 得到实体
// 判断用户名是否已经存在
userModel.find({},( err,docs ) => {
// console.log("西阁: add -> docs", docs)
// docs 就是数据库查到的结果 [{}]
const f = docs.some( item => data.username == item.username )
if ( f ) {
// 如果是true,那么数据库是有这个用户名
resolved({
status: 2,
info: '用户名已经重复'
})
} else {
// 数据库没有这个用户名
// 存数据
const userEnity = new userModel( data )
userEnity.save( err => {
if ( err ) {
rejected({
status: 0,
info: '注册失败'
})
} else {
resolved({
status: 1,
info: '注册成功'
})
}
})
}
})
})
},
del () {},
update ( data ) {
return new Promise(( resolved,rejected ) => {
// data username 新的密码 password
userModel.find({ username: data.username }, ( err,docs ) => {
// console.log('docs',docs) // [] / [{}]
if ( docs.length != 0 ) {
userModel.findById( docs[0]._id, ( err, doc ) => {
// console.log("西阁: update -> doc", doc)
doc.password = data.password
doc.save( err => {
if ( err ) {
rejected({
status: 0,
info: '修改失败'
})
} else {
resolved({
status: 1,
info: '修改成功'
})
}
})
})
} else {
// 用户名不存在的
resolved({
status: 2,
info: '用户名不存在'
})
}
})
})
},
query ( data ) {
// data是前端发过来的数据
return new Promise(( resolved,rejected ) => {
userModel.find({},( err,docs ) => {
// docs就是查询的结果 [{},{}]
const f = docs.some( item => (item.username == data.username && item.password == data.password) )
if ( f ) {
// f -> true 用户名、密码是正确的
resolved({
status: 1,
info: '登录成功'
})
} else {
// f -> false 用户名或者密码错误了
resolved({
status: 2,
info: '用户名或是密码错误'
})
}
})
})
}
}
module.exports = users
上一篇: 身无一技之长,如何选择创业项目?
推荐阅读
-
注册中医馆需要什么手续,2019申请中医馆的条件和流程!
-
商标如何在网上申请注册,网上个人商标注册流程和要求
-
YII2框架中自定义用户认证模型,完成登陆和注册操作示例
-
某盾代码js版流程分析从无感到空间点选(最后一篇轨迹加密图标以及拼图和ast)
-
jsp+java servlet实现简单用户登录和注册页面(连接数据库,登录页面包含验证码,两周内免登陆等功能)
-
免费一级域名申请的方法(*域名注册入口和流程)
-
上海注册公司的流程和费用以及所需要的材料
-
注册中医馆需要什么手续,2019申请中医馆的条件和流程!
-
UCenter实现同步登陆的原理和流程
-
javascript - 想问一下的用户登陆时用户名和密码的加密算法是什么?