25

学习后端鉴权系列: 基于Cookie, Session认证

 4 years ago
source link: https://www.tuicool.com/articles/F3AVvq6
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

说起鉴权大家应该都很熟悉, 不过作为前端开发来讲, 鉴权的流程大头都在后端小哥那边, 但是作为一个有志气的开发者肯定要好好学习整个鉴权流程以及方案, 不然怎么跟后端合作:smile:。

常见的鉴权方案

  • 基于Cookie, Session认证

  • JWT认证, Token认证

  • OAuth2认证

  • SSO单点登陆

  • LDAP认证登陆

  • 扫码登陆

基于Cookie, Session认证

关于 Cookie 使用推荐阅读,HTTP cookies。

先上大家常见的一张 Cookie , Session 流程图。

VfQbMr2.jpg!web

例子展示

下面通过node + koa + redis来展示上述的流程。

开发前准备

  • 安装node

  • 安装 redis 并且本地启动

note: 下面代码只是供demo展示, 具体代码结构设计在生产环境可不能这么写, 后面我会总结一篇关于koa最佳实践文章

启动redis

2aauyeq.jpg!web

然后通过终端查看你的redis有么有存储数据。

qiqmIrA.jpg!web

app.js

// app.js

const Koa = require("koa");
const Router = require("koa-router");
const bodyParser = require("koa-bodyparser");
const session = require("koa-session2");
const Store = require("./Store.js");

const app = new Koa();
const router = new Router();

app.keys = ["this is my secret key"];
app.use(bodyParser());

app.use(
  session({
    key: "jssessionId"
  })
);

// 模拟登陆
router.post("/login", async (ctx, next) => {
  const { username = "", password = "" } = ctx.request.body || {};
  // fake data
  const _username = "xyz";
  const _password = 123456;
  if (username === _username && password === _password) {
    const store = new Store();
    const sid = await store.set({
      username,
      password
    }, {
      maxAge: 1000 * 60 * 2 // 设定只有120s的有效时间
    });
    ctx.cookies.set('jssessionId', sid)
    ctx.body = {
      success: true,
      msg: "登陆成功"
    };
  } else {
    ctx.status = 401;
    ctx.body = {
      success: false,
      code: 10000,
      msg: "账号或者密码错误"
    };
  }
});

// 获取用户信息
router.get(
  "/user",
  async (ctx, next) => {
    const store = new Store();
    const jssessionId = ctx.cookies.get('jssessionId')
    const userSession = await store.get(jssessionId)
    console.log('获取到请求的cookie', jssessionId, 'session', userSession)
    if (!userSession) {
      ctx.status = 401;
      ctx.body = {
        success: false,
        msg: "oAuth Faill"
      };
    } else {
      ctx.userSession = userSession
      await next();
    }
  },
  async (ctx, next) => {
    ctx.body = {
      success: true,
      data: ctx.userSession
    };
  }
);

app.use(router.routes()).use(router.allowedMethods());
app.on("error", (err, ctx) => {
  console.error("server error", err, ctx);
});
app.listen(3000, () => {
  console.log("Server listening on port 3000");
});

Store.js

const Redis = require("ioredis");
const { Store } = require("koa-session2");

class RedisStore extends Store {
  constructor() {
    super();
    this.redis = new Redis(); // Connect to 127.0.0.1:6379
  }
  async get(sid, ctx) {
    try {
      const data = await this.redis.get(`jssessionId:${sid}`);
      return JSON.parse(data);
    } catch (err) {
      throw new Error(err);
    }
  }

  async set(session, { sid = this.getID(24), maxAge = 1000000 } = {}, ctx) {
    try {
      // EX: redis支持过了有效期自动删除
      await this.redis.set(
        `jssessionId:${sid}`,
        JSON.stringify(session),
        "EX",
        maxAge / 1000
      );
    } catch (err) {
      throw new Error(err);
    }
    return sid;
  }
}

module.exports = RedisStore;

然后通过postman我们来测试下

reU7nav.jpg!web

注意看返回的Set-Cookie, 接着我们看下redis

yeyYnim.jpg!web

已经存在一条数据, 另外它的有效时间是120S,过了120S该数据会自动清除。

然后我们再通过另外接口去访问用户信息。

vMZrEjz.jpg!web

是可以获取到用户信息的,说明一切正常。

120S之后再次调用该接口测试是否已经失效。

U7NBJ3Z.jpg!web

redis里面也确实自动清除了该条数据。

m2iY7ru.jpg!web

备注

有错误的地方欢迎大家斧正, 源码地址。

最后有兴趣的关注一波公众号。

eaU3qub.png!web

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK