如何在不读取标准输入的情况下使用“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)