寫一個eggjs權限驗證中間件

關於中間件

https://eggjs.org/zh-cn/basics/middleware.html
官方文檔說的很清楚了,再也不敘述。html

咱們要達到怎麼樣一個效果?

  1. 用戶沒有登陸不能訪問一些特定的頁面,好比修改密碼、修改資料啊這些敏感操做。若是用戶沒有登陸訪問這些頁面會自動跳轉到登陸頁面讓用戶登陸。
  2. 若是用戶登陸過了就能夠訪問這些頁面(驗證經過。)
  3. 沒有登陸能夠訪問登陸頁面來進行登錄,或者註冊等不須要權限的頁面。

若是不使用中間件你會怎麼寫

在controller/user 修改密碼,session

async changePassword(){
    if (this.ctx.session.userId) {  // 若是有這個session
        // 執行修改密碼
   } else {
     // 不寫就沒有響應,會404
     ctx.redirect('/login');
   }
}

而後修改資料app

async changeUserInfo(){
    if (this.ctx.session.userId) {  // 若是有這個session
        // 執行修改資料
   } else {
    // 不寫就沒有響應,會404
    ctx.redirect('/login');
   }
}

而後登陸就不用判斷async

async login(){
    let {userName, password} = this.ctx.request,body;
    // 校驗密碼
    let userFind = this.service.findOne({userName, password});
    // 獲取user信息
    if (userFind) {
        this.ctx.session.userId = userFind._id;
        // 返回成功
        this.ctx.body = '登陸成功';
    } else {
        this.ctx.body = '登陸失敗,帳號密碼錯誤';
    }
}

這樣若是代碼量小的話也能接受,可是若是未來接口愈來愈多,須要檢驗權限的地方也愈來愈多,修改就會很麻煩。this

剝離出來,自成體系

在app/middleware下面新建authLogin.js文件用來判斷是否登陸url

module.exports = (options, app) => {

  return async function testMiddleware(ctx, next) {

    let whiteUrls = options.whiteUrls || [];
    
    // 若是ctx.url在白名單中
    let isWhiteUrl = whiteUrls.some((whiteUrl)=> ctx.url.startsWith(whiteUrl));
    
    if (! isWhiteUrl) {
      console.log('authLogin');
      if (! ctx.session.userId) {
        ctx.redirect('/login');   // 讓用戶去登陸
      }
      else {
        console.log('auth ok');
        await next();
      }
    } else {
      // 白名單
      console.log('white url');
      await next();
    }
  };
};

在controller/user 修改密碼,code

async changePassword(){
    //不須要判斷,直接執行修改密碼
}

而後修改資料router

async changeUserInfo(){
    //不須要判斷,直接執行修改資料
}

而後登陸仍是同樣htm

async login(){
    let {userName, password} = this.ctx.request,body;
    // 校驗密碼
    let userFind = this.service.findOne({userName, password});
    // 獲取user信息
    if (userFind) {
        this.ctx.session.userId = userFind._id;
        // 返回成功
        this.ctx.body = '登陸成功';
    } else {
        this.ctx.body = '登陸失敗,帳號密碼錯誤';
    }
}

代碼是否是精簡清爽多了呢?中間件

注意的幾個點,

  1. 要加到config的middleware列表裏面:
config.middleware = [''authLogin'];
  1. await next()要放在最後,這樣意味着校驗規則會在路由匹配以前執行。
  2. whiteUrl是在config.default.js中的options配置,也能夠不要這個,直接使用match或者ignore(相關規則參考官方文檔關於中間件這一塊)
config.authLogin = {
    whiteUrls: ['/test'], // 是使用url的前綴匹配的
    // 不須要登陸的頁面,白名單URL
    // 也能夠使用
    ignore: ['/login', '/register', '/doLogin', '/doRegister']

    // 使用 match是限制只在這幾個頁面執行
    // match和ignore不能同時使用
  };
  1. 不配置 config.authLogin的話呢?只在特定路由中使用:
router.get('/login', authLogin, controller.user.login);

謝謝觀看,有什麼問題歡迎留言評論,看到儘可能會回覆。。。

相關文章
相關標籤/搜索