81

我正在尝试在 Docker 容器内实现自动化,但是当命令尝试读取用户名和电子邮件npm publish时收到错误消息:npm login

npm login << EOF
username
password
email
EOF

它在 Bash 终端中工作,但在容器中(没有stdin)显示错误:

Username: Password: npm ERR! cb() never called!
npm ERR! not ok code 0

根据npm-adduser

从提示中读入用户名、密码和电子邮件。

npm login不使用如何运行stdin

4

15 回答 15

49

TL;DR:直接向注册表发出 HTTP 请求:

TOKEN=$(curl -s \
  -H "Accept: application/json" \
  -H "Content-Type:application/json" \
  -X PUT --data '{"name": "username_here", "password": "password_here"}' \
  http://your_registry/-/user/org.couchdb.user:username_here 2>&1 | grep -Po \
  '(?<="token": ")[^"]*')

npm set registry "http://your_registry"
npm set //your_registry/:_authToken $TOKEN

基本原理

在幕后npm adduser向注册表发出 HTTP 请求。您可以不adduser通过 cli 直接向注册表发出请求,然后使用npm set.

源代码建议您可以http://your_registry/-/user/org.couchdb.user:your-username使用以下有效负载发出 PUT 请求

{
  name: username,
  password: password
}

这将在注册表中创建一个新用户。

非常感谢@shawnzhu 找到了一种更简洁的方法来解决问题。

于 2016-03-06T19:15:44.730 回答
38
npm set //<registry>/:_authToken $TOKEN

Github 包注册表示例:

npm set //npm.pkg.github.com/:_authToken $GITHUB_TOKEN

这是我找到的最简单的解决方案。

于 2019-10-07T14:03:19.440 回答
14

我采取了一种稍微不同的方法,似乎仍然很好用。首先,您需要一个身份验证令牌。这很容易通过在本地运行npm adduser然后从~/.npmrc位于您的用户文件夹中获取生成的令牌来获得。为了在您的 ci 服务器上进行身份验证,此身份验证令牌需要附加到用户的注册表 URL .npmrc(类似于它在本地的方式),而不是.npmrc位于存储库中,因此这些在我的 CI 配置中作为脚本步骤非常有用

- echo "//<npm-registry>:8080/:_authToken=$AUTH_TOKEN" > ~/.npmrc
- npm publish

其中 AUTH_TOKEN 在您的设置中存储为秘密变量。测试它的一个好方法是替换npm publishnpm whoamitest 并确保它成功让您登录。

这是我的整个发布配置

publish:
  stage: deploy
  only:
    - tags
  script:
    - yarn run build
    - echo "//<npm-registry>:8080/:_authToken=$NPME_AUTH_TOKEN" > ~/.npmrc
    - npm publish
    - echo 'Congrats on your publication!'

我正在使用 gitlab-ci 但我不明白为什么这不适用于任何 ci 应用程序。

于 2018-02-06T05:58:14.100 回答
14

npm-cli-login允许您在没有 STDIN 的情况下登录 NPM。

为了安装运行:

npm install -g npm-cli-login

示例用法:

npm-cli-login -u Username -p Password -e test@example.com -r https://your-private-registry-link
于 2019-02-24T11:16:31.743 回答
13

一个期望脚本对我有用。您需要确保安装了期望,这个命令应该为 ubuntu 执行此操作:

apt-get install expect-dev

您的脚本可能看起来像这样 (npm_login_expect):

#!/usr/bin/expect -f

# set our args into variables
set i 0; foreach n $argv {set "p[incr i]" $n}

set timeout 60
#npm login command, add whatever command-line args are necessary
spawn npm login
match_max 100000

expect "Username"    
send "$p1\r"

expect "Password"
send "$p2\r" 

expect "Email"
send "$p3\r"

expect {
   timeout      exit 1
   eof
}

然后这样称呼它:

expect -f npm_login_expect myuser mypassword "myuser@domain.com"
于 2015-01-23T13:21:35.340 回答
7

这适用于我的一个 devops 流程

脚步

  1. 为了安全,使用 shell 从 npm 注册表凭证生成_auth ,base 64:
    echo -n 'myuser:mypassword' | openssl base64
    Result will be something like : eWFob29vb2E=
  1. 在 npm install之前设置 npm 注册表 url 和 _auth ...
    npm config set registry https://nexus-acme.com/repository/npm-group/
    npm config set _auth eWFob29vb2E=

就这样。您可以运行npm install,您的私有模块将被下载。

于 2019-10-03T20:30:14.673 回答
5

一种解决方案是获取令牌并更新 ~/.npmrc

export ARTIFACTORY_TOKEN=`curl --silent --show-error --fail -u $ARTIFACTORY_USERNAME:$ARTIFACTORY_API_KEY https://artifactory.my.io/artifactory/api/npm/auth | \
grep -oP '_auth[\s?]=[\s?]\K(.*)$'`

echo "@my:registry=https://artifactory.my.io/artifactory/api/npm/npm-release-local/" > ~/.npmrc
echo "//artifactory.my.io/artifactory/api/npm/npm-release-local/:_auth=${ARTIFACTORY_TOKEN}" >> ~/.npmrc
echo "//artifactory.my.io/artifactory/api/npm/npm-release-local/:email=${ARTIFACTORY_USERNAME}" >> ~/.npmrc
echo "//artifactory.my.io/artifactory/api/npm/npm-release-local/:always-auth=true" >> ~/.npmrc

这可以防止从 npmjs 检索 @scope 包的问题

于 2019-07-12T22:08:08.343 回答
3

这建立在 Alexander F 的回答之上。这只是他提供的代码的简化版本,与npm-registry-client提供的示例代码混合在一起。

"use strict";

var RegClient = require('npm-registry-client')
var client = new RegClient()
var uri = "https://registry.npmjs.org/npm"
var params = {timeout: 1000}

var username = 'my.npm.username'
var password = 'myPassword'
var email = 'my.email@gmail.com'

var params = {
  auth: {
    username,
    password,
    email
  }
};

client.adduser(uri, params, function (error, data, raw, res) {
  if(error) {
    console.error(error);
    return;
  }
  console.log(`Login succeeded`);
  console.log(`data: ${JSON.stringify(data,null,2)}`);
  console.log(`NPM access token: ${data.token}`);
});
于 2018-08-29T18:44:52.990 回答
2

npm login是一种交互式方法。所以更喜欢使用npm-cli-login login

请按照以下步骤操作:

               1. npm install -g npm-cli-login
               2. npm-cli-login login -u username -p password -e abc@gmail.com -r http://registry.npmjs.org
               3. npm publish src --registry=http://registry.npmjs.org

在这里,我想将模块发布到http://registry.npmjs.org并使用我的emailid(abc@gmail.com)用户名密码在其中注册

于 2020-04-10T02:28:12.707 回答
2

很难相信,经过这么长时间,npm 登录仍然没有解决方案。当然,您可以一次获取令牌并将其用于所有 CI 需求,但是永不过期令牌的安全隐患呢?如果有一天管理员决定令牌应该过期怎么办?

下面是我使用包的 hacky javascript 解决npm-registry-client方案。只需传递一个 json 字符串参数,它就会登录并将.npmrc文件写入您当前的目录。npm logout像往常一样注销使用。

var client = new (require('npm-registry-client'))({});
var std_in = JSON.parse(process.argv[2]);

if (std_in.uri === undefined) {
    console.error('Must input registry uri!');
    return;
}

// fix annoying trailing '/' thing in registry uri
if (std_in.uri[std_in.uri.length - 1] !== '/') {
    std_in.uri = std_in.uri + '/';
}

if (std_in.scope === undefined) {
    console.error('Must input scope!');
    return;
    //std_in.scope = '@my-scope'; // or add default scope of your own
}

if (std_in.scope[0] !== '@') {
    std_in.scope = '@' + std_in.scope;
}

client.adduser(std_in.uri, std_in.params, function(err, data, raw, res) {
    if (err) {
        console.error(err);
        return;
    } 
    require('fs').writeFileSync('.npmrc', `${std_in.scope}:registry=${std_in.uri}\n//${(std_in.uri.split('//'))[1]}:_authToken=${data.token}`);
});

示例输入:

{ 
    "uri": "https://my-nmp.reg",
    "scope": "@my-scope",
    "params": {
        "auth": {
            "username": "secret-agent",
            "password": "12345",
            "email": "secret-agent@007.com"
        }
    }
}
于 2018-03-21T15:17:52.030 回答
1

取决于jq和三个 ENV 变量集:

export NPM_REGISTRY_DOMAIN=
export NPM_REGISTRY_USER=
export NPM_REGISTRY_PASSWORD=

json="{\"name\": \""$NPM_REGISTRY_USER"\", \"password\": \""$NPM_REGISTRY_PASSWORD"\"}"

TOKEN=$(curl -s \
  -H "Accept: application/json" \
  -H "Content-Type:application/json" \
  -X PUT --data "$json" \
  --user "$NPM_REGISTRY_USER":"$NPM_REGISTRY_PASSWORD" \
  https://"$NPM_REGISTRY_DOMAIN"/-/user/org.couchdb.user:"$NPM_REGISTERY_USER" | \
            jq -r '.token'
    )

npm config set registry https://"$NPM_REGISTRY_DOMAIN"
npm set //"$NPM_REGISTRY_DOMAIN"/:_authToken "$TOKEN"

基于来自https://stackoverflow.com/a/35831310/1663462的回答

于 2020-02-17T18:18:41.260 回答
1

npm login命令将所有凭据存储在全局.npmrc文件中。模式不相似,并且会发生变化。解释如下:

有两种模式,任何一种都可以。.npmrc注意:npm 存储身份验证数据可能还有其他模式,因此最好在全局上下文中交叉检查文件的内容。

每次我们做npm login一个条目,.npmrc如果它不存在。

所以这两种模式(我从.npmrc复制了以下几行)

//your_registry/:_authToken=amvasdfjkhjkjsdhflakjsdfhalskjh== //your_registry/:_authToken=NpmToken.6ca7867aba-d66a-32c0-9srr-fba908987d7987f

因此,唯一要做的就是从全局复制该行.npmrc并将其放入本地或项目中,然后从 CI.npmrc运行命令。不需要npm publish显式。npm login

于 2021-02-02T13:54:08.433 回答
0

您可以改用期望脚本或编写使用pty.js的节点脚本。

于 2014-05-04T21:01:56.717 回答
0

对于ke_wa在此重复帖子中公开的解决方案 2已经奏效。

混搭:

export NPM_USERNAME=mUs34
export NPM_PASSWORD=mypassW0rD
export NPM_EMAIL=user@domain.com
npm adduser<<!
$NPM_USERNAME
$NPM_PASSWORD
$NPM_EMAIL
!
于 2016-10-16T22:00:10.623 回答
0

我正在为此使用 gitlab-ci。

但我的私人 npm 响应没有 authtoken,因此npm-cli-login无法正常运行。

我为我的问题做了一个技巧,如下所示:

 // If no entry for the auth token is found, add one
        if (authWrite === -1) {
            lines.push(args.registry.slice(args.registry.search(/\:\/\//, '') +
            1) + '/:_authToken=' + (args.quotes ? '"' : '') + response.token + (args.quotes ? '"' : ''));
        }
        // DIY
        var loginInfo = [
            {pass: '_password'},
            {user: 'username'},
            {email: 'email'}
        ]
        loginInfo.forEach(function(ele) {
            var key = Object.keys(ele);
            lines.push(args.registry.slice(args.registry.search(/\:\/\//, '') +
            1) + '/:' + ele[key] + '=' + (args.quotes ? '"' : '') + args[key] + (args.quotes ? '"' : ''));
        })
        // DIYend
        var toWrite = lines.filter(function (element) {
            if (element === '') {
                return false;
            }
            return true;
        });

虽然它很愚蠢,但有效

于 2020-05-25T08:35:25.227 回答