zoukankan      html  css  js  c++  java
  • 写一个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);
    

    谢谢观看,有什么问题欢迎留言评论,看到尽量会回复。。。

  • 相关阅读:
    java表达式, 语句, 块(翻译自Java Tutorials)
    java控制流语句(翻译自Java Tutorials)
    你可以将使用搬到ubuntu上
    python进阶学习笔记(三)
    译:selenium webdriver (python)
    异步调用轻量级封装AsynCaller
    企业开发基础设施--事件通知服务(Remoting双向通信)
    企业开发基础设施--序
    关于跨程序集的反射
    异常处理经验谈
  • 原文地址:https://www.cnblogs.com/hengyumo/p/11134621.html
Copyright © 2011-2022 走看看