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

  1. 令牌头,找一个解密base64的网站进行解密:


    img1
  2. payload再按以上方式进行解密:


    img2
  3. 哈希,对前两者的签名,防止对其进行篡改

示例:
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里哦!!

上一篇 下一篇

猜你喜欢

热点阅读