node简易登录-token
2020-07-25 本文已影响0人
爱藏不藏
session缺点:
服务器有状态,压力大
不灵活,依赖cookie,换了环境如app或跨域怎么办
session后端有存信息,token后端没有存
index.html
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
<div>
<input v-model="username" />
<input v-model="password" />
</div>
<div>
<button v-on:click="login">Login</button>
<button v-on:click="logout">Logout</button>
<button v-on:click="getUser">GetUser</button>
</div>
<div>
<button @click="logs=[]">Clear Log</button>
</div>
<!-- ⽇日志 -->
<ul>
<li v-for="(log,idx) in logs" :key="idx">
{{ log }}
</li>
</ul>
</div>
<script>
axios.interceptors.request.use(
config => {
const token = window.localStorage.getItem("token");
if (token) {
// 判断是否存在token,如果存在的话,则每个http header都加上token // Bearer是JWT的认证头部信息
config.headers.common["Authorization"] = "Bearer " + token;}
return config;
},
err => {
return Promise.reject(err);
}
);
axios.interceptors.response.use(
response => {
app.logs.push(JSON.stringify(response.data));
return response;
},
err => {
app.logs.push(JSON.stringify(response.data));
return Promise.reject(err);
}
);
var app = new Vue({
el: "#app",
data: {
username: "test",
password: "test",
logs: [],
},
methods: {
login: async function() {
const res = await axios.post("/users/login-token", {
username: this.username,
password: this.password
});
localStorage.setItem("token", res.data.token);
},
logout: async function() {
localStorage.removeItem("token");
},
getUser: async function() {
await axios.get("/users/getUser-token");
},
} ,
});
</script>
</body>
</html>
index.js
const Koa = require('koa')
const router = require('koa-router')()
const jwt = require("jsonwebtoken")
const jwtAuth = require("koa-jwt")
const secret = "it's a secret"
const cors = require('koa2-cors')
const bodyParser = require('koa-bodyparser')
const static = require('koa-static')
const app = new Koa();
app.keys = ['some secret'];
app.use(static(__dirname + '/'));
app.use(bodyParser())
router.post("/users/login-token", async ctx => {
const { body } = ctx.request;
//登录逻辑,略略
//设置session
const userinfo = body.username;
ctx.body = {
message: "登录成功",
user: userinfo,
// ⽣生成 token 返回给客户端
token: jwt.sign(
{
data: userinfo,
// 设置 token 过期时间,⼀一⼩小时后,秒为单位
exp: Math.floor(Date.now() / 1000) + 60 * 60,
},
secret
)
}
});
router.get("/users/getUser-token",
jwtAuth({secret}),
async ctx => {
// 验证通过,state.user
console.log(ctx.state.user);
//获取session
ctx.body = {
message: "获取数据成功",
userinfo: ctx.state.user.data,
};
}
);
app.use(router.routes());
app.use(router.allowedMethods());
app.listen(3000);
jwtAuth({secret})
通过这个方式验权,并将token信息传给ctx.state
看一个加密后的token,以“.”隔开分为3个部分(令牌头、payload、哈希)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJkYXRhIjoidGVzdCIsImV4cCI6MTU5NTY1Mjg5NywiaWF0IjoxNTk1NjQ5Mjk3fQ.
Xu8ZCe-Tx9c9VJQdusS8jfoX4RqUNgCkGDy1u8npUhA
-
令牌头,找一个解密base64的网站进行解密:
img1
-
payload再按以上方式进行解密:
img2
- 哈希,对前两者的签名,防止对其进行篡改
示例:
jsonwebtoken.js
const jsonwebtoken = require('jsonwebtoken')
const secret = '12345678'
const opt = {
secret: 'jwt_secret',
key: 'user' }
const user = {
username: 'abc',
password: '111111'
}
const token = jsonwebtoken.sign({
data: user,
// 设置 token 过期时间
exp: Math.floor(Date.now() / 1000) + (60 * 60),
}, secret)
console.log('⽣生成token:' + token)
// TODO 在这里修改token试试
token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7InVzZXJuYW1lIjoiYWJjIiwicGFzc3dvcmQiOiIxMTExMTEifSwiZXhwIjoxNTk1NjU0MTM3LCJpYXQiOjE1OTU2NTA1Mzd9.slKscfarE09OaXdC1LGnyezxKnAyMdYJDQXSedZ42Ec';
console.log('解码:', jsonwebtoken.verify(token, secret, opt))
以上运行能看到解码结果,但是如果随便修改一点token的值,运行就会报错!
注意
密码不能放token里哦!!