寫一個eggjs權限驗證中間件


關於中間件

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

我們要達到怎么樣一個效果?

  1. 用戶沒有登錄不能訪問一些特定的頁面,比如修改密碼、修改資料啊這些敏感操作。如果用戶沒有登錄訪問這些頁面會自動跳轉到登錄頁面讓用戶登錄。
  2. 如果用戶登錄過了就可以訪問這些頁面(驗證通過。)
  3. 沒有登錄可以訪問登錄頁面來進行登陸,或者注冊等不需要權限的頁面。

如果不使用中間件你會怎么寫

在controller/user 修改密碼,

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

然后修改資料

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

然后登錄就不用判斷

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 = '登錄失敗,賬號密碼錯誤';
  	}
}

這樣如果代碼量小的話也能接受,但是如果將來接口越來越多,需要檢驗權限的地方也越來越多,修改就會很麻煩。

剝離出來,自成體系

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

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 修改密碼,

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

然后修改資料

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

然后登錄還是一樣

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);

謝謝觀看,有什么問題歡迎留言評論,看到盡量會回復。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM