3 koa2 实战鉴权

课程目标

  • 掌握三种常见鉴权方式:Session/Cookie、Token、OAuth

session-cookie方式

  • 原理

1 登录 -> 服务端生成sid(内存或者redis中) -> 主动设置sid或者返回给客户端 -> 客户端带着sid发送请求 -> sid匹配认证是否通过

  • koa中使用
app.keys = ['some secret', 'another secret'];

const SESS_CONFIG = {
 key: 'kkb:sess',
 maxAge: 86400000,
 httpOnly: true,
 signed: true,
};
app.use(session(SESS_CONFIG, app));
app.use(ctx => {
 if (ctx.path === '/favicon.ico') return;
 let n = ctx.session.count || 0;
 ctx.session.count = ++n;
 ctx.body = '第' + n + '次访问';
});
  • 使用redis存储session

    • 安装: npm i -S koa-redis
    • 配置使用:
const redisStore = require('koa-redis');
const redis = require('redis')
const client = redis.createClient(6379, "localhost");
app.use(session({
 key:'kkb:sess',
 store: redisStore({client})
}, app));
app.use(ctx => {
 //...
 client.keys('*',(err,keys)=>{
  console.log(keys);
  keys.forEach(key=>{
   client.get(key,(err,val)=>{
    console.log(val);
  })
 })
})
});
  • 案例:通过session实现用户鉴权

    • 登录页面,./public/login.html
<!DOCTYPE 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 @click="login">Login</button>
            
        <button @click="logout">Logout</button>
            
        <button @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.defaults.withCredentials = true;
    axios.interceptors.response.use(response => {
        app.logs.push(JSON.stringify(response.data));
        return response;
    });
    var app = new Vue({
        el: "#app",
        data: {
            username: "test",
            password: "test",
            logs: []
        },
        methods: {
            login: async function () {
                await axios.post("/users/login", {
                    username: this.username,
                    password: this.password
                });
            },
            logout: async function () {
                await axios.post("/users/logout");
            },
            getUser: async function () {
                await axios.get("/users/getUser");
            }
        }
    });
</script>
 
</body>
</html>
  • 登录页面,./public/login.html
router.post("/login", async ctx => {
 const { body } = ctx.request;
 console.log("body", body);
 ctx.session.userinfo = body.username;
 ctx.body = {
  ok: 1,
  message: "登录成功"
};
});
router.post("/logout", async ctx => {
 delete ctx.session.userinfo;
 ctx.body = {
  ok: 1,
  message: "登出系统"
};
});
router.get("/getUser", async ctx => {
  ctx.body = {
   ok: 1,
   message: "获取数据成功",
   userinfo: ctx.session.userinfo
 };
});
  • 路由守卫中间件,./middleware/auth.js
module.exports = async (ctx, next) => {
 if (!ctx.session.userinfo) {
  ctx.body = {
   ok: 0,
   message: "用户未登录"
 };
} else {
  await next();
}
};
  • 应用守卫,./routes/users.js
router.get("/getUser", require("./middleware/auth"), async ctx => {...})

Token 验证

  • 原理

  • 案例:令牌认证

    • 登录页,public/login-token.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>
我来评几句
登录后评论

已发表评论数()

相关站点

热门文章