如何在不读取标准输入的情况下使用“npm login”设置 npm 凭据?

Posted

技术标签:

【中文标题】如何在不读取标准输入的情况下使用“npm login”设置 npm 凭据?【英文标题】:How to set npm credentials using `npm login` without reading from stdin? 【发布时间】:2014-06-21 01:50:06 【问题描述】:

我正在尝试在 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:

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

如何在不使用stdin 的情况下运行npm login

【问题讨论】:

您的命令实际上对我有用,谢谢! :) 唯一缺少的是添加 --repository 参数... 【参考方案1】:

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 设置身份验证令牌。

The source code suggests,您可以使用以下有效负载向http://your_registry/-/user/org.couchdb.user:your-username 发出 PUT 请求


  name: username,
  password: password

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

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

【讨论】:

这很聪明,但在我的情况下似乎不起作用。我们正在使用 ProGet 并且该命令的输出 see 仅返回和对象,如 "ok":"true" 并且没有任何标记。似乎 proget 更改了该命令的响应...如果我发现任何内容,我会及时通知您。 如果我们只想登录而不添加新用户怎么办?通过上述 PUT 请求,我得到了 bcak“用户存在”。 得到了解决方案:github.com/rlidwka/sinopia/issues/329#issuecomment-217406747 如果您已经使用npm login 登录,则可以在您的主文件夹中的文件~/.npmrc 中找到令牌的信息。然后,只有npm set //your-registry.com/:_authToken="wKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=" 还有其他人遇到此解决方案不起作用的问题吗?我总是收到“您无权发布..”【参考方案2】:
npm set //<registry>/:_authToken $TOKEN

Github 包注册表示例:

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

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

【讨论】:

这是完美的解决方案 github 操作用户注意事项:秘密可通过$ secrets.SECRET_NAME 访问,因此您需要npm set "//registry.npmjs.org/:_authToken" $ secrets.NPM_TOKEN_OR_WHATEVER docker 用户注意事项:docker build 可能会将 NPM_TOKEN 的明文值记录到您的控制台/ci 日志中。您可以通过将此命令放入 ./npm-config.sh 并改为执行该命令来避免这种情况。【参考方案3】:

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

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

AUTH_TOKEN 在您的设置中存储为秘密变量。 一个很好的测试方法是将npm publish 替换为npm whoami 以测试并确保它成功登录。

这是我的整个发布配置

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 应用程序。

【讨论】:

npm ping 已精确设置为允许测试连接性和凭据。另请注意,有时将其输出到本地 .npmrc 文件而不是始终将其放在用户的 HOME 文件夹中会很有用——尤其是为了避免仅仅因为运行了一些自动化命令而破坏用户的正常日常配置。跨度> 【参考方案4】:

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

【讨论】:

【参考方案5】:

一个期望脚本对我有用。你需要确保安装了期望,这个命令应该为 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"

【讨论】:

是的,如果有expect 可以读取的tty。我的问题是,根本没有 STDIN 或 sudo tty。 在厨师食谱中也有过款待。 我收到错误:spawn npm login npm ERR! wrong # args: should be "eof channelId" while executing "eof" invoked from within "expect timeout exit 1 eof " (file "npm_login.sh" line 20)【参考方案6】:

这在我的一个 devops 流程中有效

步骤

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

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

【讨论】:

这对我根本不起作用......我在我的 .npmrc 文件中有它并尝试 npm install 仍然身份验证错误。 你的 nodejs 版本是多少?删除旧的 .npmrc 并重试! 为我工作,无需任何互联网访问即可登录 Nexus 私人注册表。【参考方案7】:

一种解决方案是获取令牌并更新 ~/.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 包的问题

【讨论】:

【参考方案8】:

这建立在 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`);
);

【讨论】:

【参考方案9】:

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

以下是我使用 npm-registry-client 包的 hacky javascript 解决方案。只需传递一个 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"
        
    

【讨论】:

【参考方案10】:

npm login 是一种交互式方法。所以更喜欢使用 npm-cli-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)用户名 和 密码

【讨论】:

【参考方案11】:

取决于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://***.com/a/35831310/1663462的回答

【讨论】:

【参考方案12】:

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

【讨论】:

谢谢。根本原因是npm adduser 总是从标准输入请求我无法输入的输入。然后我找到了另一种方法,它是一种生成工作~/.npmrc 的技巧。见github.com/npm/npm-registry-client/blob/master/lib/… @shawnzu 如果您将解决方案发布到互联网的其余部分会很好,因为您提供的链接使用 master 而不是 sha,所以它现在已经过时了:( 【参考方案13】:

对于ke_wa 在这个duplicated post 中公开的解决方案2 已经奏效了。

混搭:

export NPM_USERNAME=mUs34
export NPM_PASSWORD=mypassW0rD
export NPM_EMAIL=user@domain.com
npm adduser<<!
$NPM_USERNAME
$NPM_PASSWORD
$NPM_EMAIL
!

【讨论】:

不适合我。我不断收到Username: Password: npm ERR! cb() never called!【参考方案14】:

我正在为此使用 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;
        );

虽然很傻,但是很有效

【讨论】:

【参考方案15】:

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

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

每次我们执行npm login 时,都会在.npmrc 中创建一个条目(如果它不存在)。

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

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

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

【讨论】:

以上是关于如何在不读取标准输入的情况下使用“npm login”设置 npm 凭据?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用重定向的标准输入读取文件,即 cin(注意:不使用 ifstream)

如何在不使用 node.js 的情况下添加标准反应应用程序 [关闭]

如何在不知道数组大小的情况下初始化数组?

从标准输入读取密码

在不读取整个文件的情况下获取图像尺寸

在不读取整个文件的情况下获取图像尺寸