什么叫做登录鉴权呢?
众所周知http协议是无状态的,下一次链接与本次链接没有任何联系,那么这样的话,服务器就不知道客户端的一些情况(比如用户之前登录过,现在是否还有登录状态),所以需要采用一些方法去保留这种登录状态。这些方法就叫登录鉴权。
JWT策略
jwt 又称json web token。 它由三部分组成,中间以两个逗号隔开.分别为头部,负载,和签名。
//大概是这个样子
fcf21f1515d54e6791810b2166c38ece,d169ae7e5c074a6ca020667c32e3f58a,6ca020667c32e3f58a
组成
三部分具体是怎么组成的呢?
头部
原始为json对象,里面有两个字段,type指策略(jwt),加密算法,(这个后面签名部分会用到) 这里还采用一种编码方式(一般是base64)进行编码,对json对象编码形成字符串。这样构成第一部分
负载
也是json对象,主要是一些用户信息,方便之后解码以后去对照鉴权,去快速查询数据库。还有一部分是token的配置信息,如过期时间,生效时间等。如上这里还采用一种编码方式(一般是base64)进行编码生成字符串。
签名
这个是利用,头部的加密算法,一个服务器保存的密钥,对头部,负载部分的字符串进行加密,从而生成第三部分
实现过程
步骤
当客户端第一次请求服务端,需要进入到登录页面,此时,用户输入账号密码进行登录,先到数据库查询账户密码,如果存在,并且对了,就生成token发送到客户端,一般存在浏览器localstorage里面
后续客户端发送请求,需要带上token,一般放在请求头里面的Authorization,服务端去验证,如果没有token就证明没登录态。
//这里我用前端的egg框架去举例子
async login() {
const username = this.ctx.query.username;
const password = this.ctx.query.password;
const sel = await this.app.mysql.get('user', { username });
//先获取账户密码,然后去查询数据库如果没查到报错
let msg = {};
if (sel == null) {
msg = {
code: 1001,
data: {
message: '账号不存在',
},
};
} else if (sel.password == password) {
//这里就是关键的生成token的代码。将username,作为数据负载穿进去,编码。调用了 egg的jwt包,可以快速生成,解码。这里的插件采用默认的编码,默认的生效时间,过期时间等。
const token = this.app.jwt.sign(username, this.app.config.jwt.secret);
msg = {
code: 200,
data: {
message: '登录成功',
token,
},
};
} else {
msg = {
code: 1002,
data: {
message: '密码错误',
},
};
}
return msg;
}
//验证token
module.exports = () => {
return async function jwtErr(ctx, next) {
const token = ctx.request.header.token;
console.log(ctx.request.header.token);
let decode = '';
if (token) {
try {
// 解码token
decode = ctx.app.jwt.verify(token, '123456');// 验证token
// 绑定这个中间件的接口 ,就可以获取赋值之后的username;
ctx.username = decode;
await next();
console.log('decode======>', decode);
} catch (error) {
ctx.status = 1004;
ctx.body = {
message: '解析失败' + error.message,
};
return;
}
} else {
ctx.status = 1005;
ctx.body = {
message: '没有token',
data: ctx.request.header,
};
return;
}
};
};
cookie,session策略
然后再来说一下cookie,session策略,两者相比最大的差别应该是,存储地方不同,客户端登录过后,服务端会开辟出一片区域存储信息,并生成一个sessionId去标识这一个信息。并把sessionId返回给客户端。客户端存在cookie里面在每次发送请求时候自动带给服务端。这样服务端就可以从cookie中的sessionid换取用户信息,从而判断登录态。
const express = require('express');
const session = require('express-session');
//中间件
const sessions = require('express-session');
const app = express();
//app use去应用中间件
app.use(express.json());
app.use(express.urlencoded({extended:true}));
const username ='hei';
const password = '123';
var mysession;
app.use(session({
secret:'heihei',//签名
name:'heihei',
cookie:{maxAge:15000},
resave:false,
saveUninitialized:false
}))
//监听访问
app.get('/',(req,res)=>{
console.log('访问网页');
mysession =req.session;
if(mysession.username){
res.send(`欢迎回来${mysession.username}
<a href='/logout'>登出</a>
`)
}else{
res.send('你好新用户')
}
})
app.post('/login',(req,res)=>{
if(req.body.username ===username&&req.body.password===password){
mysession = req.session;
mysession.username = 'hei';
console.log('中间件生成session',req.session,req.sessionID);
res.send(`欢迎回来${mysession.username}
<a href='/logout'>登出</a>
`)
}
else {
res.send(`密码错误
`)
}
})
app.get('/logout',(req,res)=>{
req.session.destroy();//清除session
console.log(`登出,${req.session}`)
res.redirect('/')
})
app.listen('3001',()=>console.log('3001 running!'));