使用 NKey 进行身份验证
NATS 服务器的 2.0 版本引入了一种新的质询响应身份验证选项。这种质询响应基于我们称之为 NKeys 的封装器。服务器可以以多种方式使用这些密钥进行身份验证。最简单的方式是将服务器配置为包含已知公钥列表,客户端则通过使用其私钥对质询进行签名来响应。(可打印的私有 NKey 称为种子)。这种质询响应通过确保客户端拥有私钥来保证安全性,同时也保护了私钥不被服务器访问,因为服务器永远不会接触到它!
处理质询响应可能需要在连接选项中进行更多设置,具体取决于客户端库。
{% tabs %}
{% tab title="Go" %}
opt, err := nats.NkeyOptionFromSeed("seed.txt")
if err != nil {
log.Fatal(err)
}
nc, err := nats.Connect("127.0.0.1", opt)
if err != nil {
log.Fatal(err)
}
defer nc.Close()
// 使用连接做一些事情
{% endtab %}
{% tab title="Java" %}
NKey theNKey = NKey.createUser(null); // 应该从某个地方加载
Options options = new Options.Builder()
.server("nats://localhost:4222")
.authHandler(new AuthHandler(){
public char[] getID() {
try {
return theNKey.getPublicKey();
} catch (GeneralSecurityException|IOException|NullPointerException ex) {
return null;
}
}
public byte[] sign(byte[] nonce) {
try {
return theNKey.sign(nonce);
} catch (GeneralSecurityException|IOException|NullPointerException ex) {
return null;
}
}
public char[] getJWT() {
return null;
}
})
.build();
Connection nc = Nats.connect(options);
// 使用连接做一些事情
nc.close();
{% endtab %}
{% tab title="JavaScript" %}
// 种子应被视为密码并妥善保存
const seed = new TextEncoder().encode(
"SUAEL6GG2L2HIF7DUGZJGMRUFKXELGGYFMHF76UO2AYBG3K4YLWR3FKC2Q",
);
const nc = await connect({
port: ns.port,
authenticator: nkeyAuthenticator(seed),
});
{% endtab %}
{% tab title="Python" %}
nc = NATS()
async def error_cb(e):
print("Error:", e)
await nc.connect("nats://localhost:4222",
nkeys_seed="./path/to/nkeys/user.nk",
error_cb=error_cb,
)
# 使用连接做一些事情
await nc.close()
{% endtab %}
{% tab title="C#" %}
// dotnet add package NATS.Net
using NATS.Net;
using NATS.Client.Core;
await using var client = new NatsClient(new NatsOpts
{
Url = "127.0.0.1",
Name = "API NKey Example",
AuthOpts = new NatsAuthOpts
{
NKeyFile = "/path/to/nkeys/user.nk"
}
});
{% endtab %}
{% tab title="C" %}
static natsStatus
sigHandler(
char **customErrTxt,
unsigned char **signature,
int *signatureLength,
const char *nonce,
void *closure)
{
// 对给定的 `nonce` 进行签名,并将签名作为 `signature` 返回。
// 这需要分配内存。签名的长度通过 `signatureLength` 返回。
// 如果发生错误,用户可以通过 `customErrTxt` 返回特定的错误信息。库会释放这个指针。
return NATS_OK;
}
(...)
natsConnection *conn = NULL;
natsOptions *opts = NULL;
natsStatus s = NATS_OK;
const char *pubKey = "my public key......";
s = natsOptions_Create(&opts);
if (s == NATS_OK)
s = natsOptions_SetNKey(opts, pubKey, sigHandler, NULL);
if (s == NATS_OK)
s = natsConnection_Connect(&conn, opts);
(...)
// 销毁创建的对象
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
{% endtab %}
{% endtabs %}