使用verdaccio搭建npm私服

2,559 阅读6分钟

一、为什么要搭建npm私服

  • 随着前端团队的发展,可复用的工具或者组件会变得越来越多,因为可能会涉及一些敏感的业务信息,所以肯定不能放到npm仓库,那么就要搭建一个私服
  • 很多公共的东西总是会迭代更新,没有一个地方集体管理的话,那么会出现版本不统一的现象,造成管理混乱的现象
  • 私服能够将包资源进行缓存,响应的就会提高下载速度
  • 搭建一个npm私服算是对整个团队的技术沉淀的一种积累

二、搭建私服的步骤

  • 首先确保已经安装过node,同时要保证node是8.x以上版本
  • 安装verdaccio私服搭建工具

npm i -g verdaccio

当安装完成之后,会在/Users/admin/.config路径下增加一个verdaccio的文件夹

image.png

此时在文件中存在两个文件,一个是config.yaml另外一个是storage

  • 首先来看config.yaml文件夹,这是verdaccio的配置文件,里面有默认的配置,下面只对常用配置做说明

    storage: ./storage // 指定当前私服上包的缓存地址是哪,默认是storage文件夹

    // 指定当前verdaccio使用的插件所在的地址,默认是plugins文件夹,但是此项配置只对使用docker部署有用 // 单独启动verdaccio时,插件不能放在这里,会造成读不到插件的错误 plugins: ./plugins

    // 对verdaccio可视化界面的配置,可以配置title或者gravatar web: title: Verdaccio

    // 设置权限组 // htpasswd是verdaccio自带的鉴权插件,当初次启动之后,会在verdaccio文件夹下生成htpasswd文件 // htpasswd存储了可登录私服的用户信息 auth: htpasswd: file: ./htpasswd

    // 上游链路设置 // 当用户下载源设置为私服的地址时,可能会存在某个包在私服上是没有的,那么此时就可以通过上游链路去下载 uplinks:

    // 此处可以配置多个上游链路 npmjs: url: npm.taobao.org/

    // 设置对每一类包的权限分配情况, packages:

    // 需要将具名的包放到前面,因为读取顺序是从上往下,否则权限控制可能出错
    

    // 通过关键字来匹配包名,比如'@demo/' 就可以匹配 '@demo/demo' '@/*':

    // access设置哪些用户可以下载包以及可以在私服上看到包的信息;$all表示不管登录与否都有权限
    access: $all
    
    // publish设置哪些用户可以发布包;$authenticated表示登录的用户
    publish: $authenticated
    
    // unpublish设置哪些用户可以删除包;$anonymous表示未登录的用户
    unpublish: $anonymous
    
    // proxy设置需要使用哪些上游链路,当私服没有时就会从上游链路中下载,此处上游链路可写多个,
    // 从左到右一次生效
    proxy: npmjs
    

    '**': access: allpublish:all publish: authenticated unpublish: $authenticated proxy: npmjs

    // 设置verdaccio开启的端口,如果需要其他人也能访问,那么需要写成如下形式
    

    listen: 0.0.0.0:4873

补充:当在为包配置权限的时候,除了allall,authenticated,$anonymous可选,也可以写具体的用户名,当然也可以更改权限组的配置方式,下面会说插件的使用和开发

  • 安装完之后,就可以直接开启verdaccio,直接命令行输入verdaccio即可

verdaccio

启动之后,会返回配置文件位置信息,所启用的插件信息,以及地址信息和verdaccio的版本号

image.png

  • 此时就完成了基本的私服搭建,可以将npm源设置为私服的地址,进行包的发布和删除

  • 可以在项目中的.npmrc文件设置源

  • 也可以下载nrm源管理工具,快速的切换npm源

三、如何完成私服权限管理

  • 因为verdaccio默认是人人都可以注册的,所以需要先将注册窗口关闭

    auth: htpasswd: file: ./htpasswd // 此配置项可以关闭注册功能 max_users: -1

  • 同时使用htpasswd插件所提供的工具(hostingcanada.org/htpasswd-ge…),为相应的用户生成用户名和密码,之后将用户名和密码写入verdaccio文件夹下的htpasswd文件中;那么此时只有这些被添加的用户可以登录私服

image.png

  • 之后就需要修改verdaccio文件下的config.yaml的配置:针对不同的包来设置access,publish,unpublish对应的权限组,因为htpasswd是默认的鉴权插件,所以只能写入相应的用户名,allall,authenticated,$anonymous

    packages: '@/': // 下载权限开放给所有人 access: all//publish的权限只开放给登录的人publish:all // publish的权限只开放给登录的人 publish: authenticated // unpublish的权限只开放给特定的用户 unpublish: xiaoming proxy: npmjs

    '**': access: allpublish:all publish: authenticated unpublish: $authenticated proxy: npmjs

  • 当需要管理的包很多同时每一种权限又需要细分用户时,或者对于一些权限组会平凡更改不同用户的话,配置起来可能会比较麻烦,这里就需要插件的帮忙;通过插件将用户进行分组形成一个个用户组,然后再用这些用户组去配置不同的权限

    auth: htpasswd: file: ./htpasswd // 此配置项可以关闭注册功能 max_users: -1 duGroup: // 这里可以自定义用户组 demoPublish: [xiaoming, xiaohong, xiaoli] demoUnpublish: [xiaojun, xiaoming] testPublish: [xiaoming,xiaojun]

    packages: '@demo/*': access: all//针对不同的包,可以指定不同的用户组来满足权限控制publish:demoPublishunpublish:demoUnpublishproxy:npmjstest:access:all // 针对不同的包,可以指定不同的用户组来满足权限控制 publish: demoPublish unpublish: demoUnpublish proxy: npmjs 'test': access: all publish: testPublish unpublish: demoUnpublish proxy: npmjs

  • 接下来说一下插件的使用和开发

  • 插件的使用:当需要使用一个插件时,需要将插件包放到有verdaccio依赖的全局的node_modules文件夹中,否则启动verdaccio时会报错,提示找不到对应的插件

  • 插件的开发:首先verdaccio的插件要遵循指定的规则,有一个简单的方式就是通过yo工具,可以直接生成一个符合verdaccio插件规则的模板

  • npm i -g yo npm i -g generator-verdaccio-plugin (此工具生成的模板,需要进行手动改动,因为不太符合文档里的要求)

  • 以下是自己写的一个插件用来将用户分成用户组,然后来分配权限(插件地址:github.com/weijunran/v…)

    const createError = require('http-errors');

    class DynamicGroupPlugin { constructor(config, stuff) { // config插件接收的配置项 // stuff整个config.yaml的配置项 this.pluginsConfig = config } //检查当前权限下是否有配置 checkPkgAction(pkg,action){ return pkg[action] == null } //判断权限函数 authenticate(action) { return (user, pkg, cb)=>{ let { name:userName,groups:userGroups } = user let authArr = pkg[action] let isTrue = authArr.some((authItem)=>{ if(authItem === userName){ return true } else if(userGroups.includes(authItem)){ return true } else{ let key = authItem; let pluginsArr = this.pluginsConfig[${key}] return pluginsArr!=null && pluginsArr.some((item)=>{ if(item === userName){ return true } }) } })

      if(isTrue){
        // 如果符合,就用以下形式回调给verdaccio
        return cb(null, true);
      }
    
      if (userName) {
        // 如果不符合可以给回调传递错误信息
        cb(createError(403, `user ${userName} is not allowed to ${action} package ${pkg.name}`));
      } else {
        cb(createError(401, `authorization required to ${action} package ${pkg.name}`));
      }
    }
    

    }

    allow_access(user, pkg, cb) { let action = 'access'; if(this.checkPkgAction(pkg,action)){ return cb(null, false) } // in case of restrict the access return this.authenticate(action)(user,pkg,cb) }

    allow_publish(user, pkg, cb) { let action = 'publish'; if(this.checkPkgAction(pkg,action)){ return cb(null, false) } // in cass to check if has permission to publish return this.authenticate(action)(user,pkg,cb) }

    allow_unpublish(user, pkg, cb){ let action = 'unpublish'; if(this.checkPkgAction(pkg,action)){ return cb(null, false) } return this.authenticate(action)(user,pkg,cb) }

    }

    module.exports = (cfg, stuff) => new DynamicGroupPlugin(cfg, stuff);

四、总结

       首先verdaccio的文档描述并不是那么的全面,而且感觉上没有得到及时的更新,而且其实还有很多问题是没有被得到解决的,但是对于只是需要配置简单的权限,并且只想用免费的工具来快速搭建npm私服的话,那么verdaccio感觉是比较适合的。