对服务器进行身份验证

本主题介绍在使用 Snowflake SQL API 时如何对服务器进行身份验证。

发送请求时,请求必须包含身份验证信息。以下各部分说明如何将此信息添加到请求中:

本主题内容:

使用 OAuth

若要使用 OAuth,请按照下列步骤操作:

  1. 设置 OAuth 进行身份验证。

    有关如何设置 OAuth 和获取 OAuth 令牌的详细信息,请参阅 OAuth 简介

  2. 使用 SnowSQL 验证可以使用生成的 OAuth 令牌连接到 Snowflake:

    • 对于 Linux 和 MacOS 系统

    $ snowsql -a <account_identifier> -u <user> --authenticator=oauth --token=<oauth_token>
    
    Copy
    • 对于 Windows 系统

    $ snowsql -a <account_identifier> -u <user> --authenticator=oauth --token="<oauth_token>"
    
    Copy
  3. 在发送的每个 API 请求中,设置以下标头:

    • Authorization: Bearer oauth_token

      其中 oauth_token 是生成的 OAuth 令牌。

    • X-Snowflake-Authorization-Token-Type: OAUTH

      请注意,也可以选择省略 X-Snowflake-Authorization-Token-Type 标头。如果此标头不存在,则 Snowflake 假定 Authorization 标头中的令牌是 OAuth 令牌。

使用密钥对身份验证

若要使用密钥对身份验证,请按照下列步骤操作:

  1. 设置密钥对身份验证。

    在此过程中,您必须执行以下操作:

    1. 生成公钥-私钥对。生成的私钥应位于文件中(例如,名为 rsa_key.p8)。

    2. 将公钥分配给 Snowflake 用户。将密钥分配给用户后,运行 DESCRIBE USER 命令。在输出中, RSA_PUBLIC_KEY_FP 属性应设置为分配给用户的公钥的指纹。

    有关如何生成密钥对并将密钥分配给用户的说明,请参阅 密钥对身份验证和密钥对轮换。有关创建指纹和生成 JWT 令牌的语言特定示例,请参阅以下内容:

  2. 使用 SnowSQL 验证可以使用生成的私钥 连接到 Snowflake

    $ snowsql -a <account_identifier> -u <user> --private-key-path <path>/rsa_key.p8
    
    Copy

    如果生成了加密的私钥, SnowSQL 会提示输入生成密钥时创建的密码。

  3. 在应用程序代码中,执行以下操作:

    1. 为用户生成公钥的指纹( SHA-256 哈希值)。在指纹前加上 SHA256:。例如:

      SHA256:hash

      还可以执行 SQL DESCRIBE USER 命令从 RSA_PUBLIC_KEY_FP 属性中获取值。

    2. 生成 一个 JSON Web 令牌 (JWT) (link removed),其有效负载中包含以下字段:

      字段

      描述

      示例

      iss

      JWT 的发放者。将其设置为以下值:

      account_identifier.user.SHA256:public_key_fingerprint

      其中:

      • account_identifier 是 Snowflake 账户标识符

        如果使用的是 账户定位器,请从账户定位器中排除任何区域信息。

      • user 是 Snowflake 用户名。

      • SHA256:public_key_fingerprint 是在上一步中生成的指纹。

      备注

      account_identifieruser 值必须全部使用大写字符。如果您的账户 ID 包含句点 (.),必须用连字符 (-) 将其替换,因为账户标识符中的句点会导致 JWT 无效。

      MYORGANIZATION-MYACCOUNT.MYUSER.SHA256:public_key_fingerprint

      sub

      JWT 的主题。将其设置为以下值:

      account_identifier.user

      MYORGANIZATION-MYACCOUNT.MYUSER

      iat

      JWT 的发放时间(以 UTC 表示)。将该值设置为当前时间值,以秒或毫秒为单位。

      1615370644 (秒) . 1615370644000 (毫秒)

      exp

      JWT 的过期时间(以 UTC 表示)。 可以将该值指定为秒或毫秒。

      备注

      即使指定了更长的过期时间, JWT 在令牌颁发后最多一个小时内有效。

      1615374184 (秒) . 1615374184000 (毫秒)

    3. 在发送的每个 API 请求中,设置以下标头:

      • Authorization: Bearer JWT

        其中 JWT 是生成的令牌。

      • X-Snowflake-Authorization-Token-Type: KEYPAIR_JWT

Python 示例

以下部分介绍如何使用 Python 生成 JWT 和指纹。

有关在 Python 中生成 JWT 的示例,请参阅 sql-api-generate-jwt.pysql-api-generate-jwt.py 示例使用 ` PyJWT 模块 <https://pypi.org/project/PyJWT/ (https://pypi.org/project/PyJWT/)> `_,可以通过运行以下命令安装该模块:

pip install pyjwt
Copy

在 Python 中生成 JWT

以下代码部分演示了如何生成 JWT。有关完整示例,请参阅 sql-api-generate-jwt.py

备注

此示例仅供参考。请勿在生产应用程序或环境中使用此代码。

from datetime import timedelta, timezone, datetime

# This example relies on the PyJWT module (https://pypi.org/project/PyJWT/).
import jwt

# Construct the fully qualified name of the user in uppercase.
# - Replace <account_identifier> with your account identifier.
#   (See https://docs.snowflake.com/en/user-guide/admin-account-identifier.html .)
# - Replace <user_name> with your Snowflake user name.
account = "<account_identifier>"

# Get the account identifier without the region, cloud provider, or subdomain.
if not '.global' in account:
    idx = account.find('.')
    if idx > 0:
        account = account[0:idx]
    else:
        # Handle the replication case.
        idx = account.find('-')
        if idx > 0:
            account = account[0:idx]

# Use uppercase for the account identifier and user name.
account = account.upper()
user = "<user_name>".upper()
qualified_username = account + "." + user

# Get the current time in order to specify the time when the JWT was issued and the expiration time of the JWT.
now = datetime.now(timezone.utc)

# Specify the length of time during which the JWT will be valid. You can specify at most 1 hour.
lifetime = timedelta(minutes=59)

# Create the payload for the token.
payload = {

    # Set the issuer to the fully qualified username concatenated with the public key fingerprint (calculated in the  previous step).
    "iss": qualified_username + '.' + public_key_fp,

    # Set the subject to the fully qualified username.
    "sub": qualified_username,

    # Set the issue time to now.
    "iat": now,

    # Set the expiration time, based on the lifetime specified for this object.
    "exp": now + lifetime
}

# Generate the JWT. private_key is the private key that you read from the private key file in the previous step when you generated the public key fingerprint.
encoding_algorithm="RS256"
token = jwt.encode(payload, key=private_key, algorithm=encoding_algorithm)

# If you are using a version of PyJWT prior to 2.0, jwt.encode returns a byte string, rather than a string.
# If the token is a byte string, convert it to a string.
if isinstance(token, bytes):
  token = token.decode('utf-8')
decoded_token = jwt.decode(token, key=private_key.public_key(), algorithms=[encoding_algorithm])
print("Generated a JWT with the following payload:\n{}".format(decoded_token))
Copy

在 Python 中生成指纹

以下代码部分演示了如何生成指纹。有关完整示例,请参阅 sql-api-generate-jwt.py

from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.primitives.serialization import Encoding
from cryptography.hazmat.primitives.serialization import PublicFormat
from cryptography.hazmat.backends import default_backend
..
import base64
from getpass import getpass
import hashlib
..
# If you generated an encrypted private key, implement this method to return
# the passphrase for decrypting your private key. As an example, this function
# prompts the user for the passphrase.
def get_private_key_passphrase():
    return getpass('Passphrase for private key: ')

# Private key that you will load from the private key file.
private_key = None

# Open the private key file.
# Replace <private_key_file_path> with the path to your private key file (e.g. /x/y/z/rsa_key.p8).
with open('<private_key_file_path>', 'rb') as pem_in:
    pemlines = pem_in.read()
    try:
        # Try to access the private key without a passphrase.
        private_key = load_pem_private_key(pemlines, None, default_backend())
    except TypeError:
        # If that fails, provide the passphrase returned from get_private_key_passphrase().
        private_key = load_pem_private_key(pemlines, get_private_key_passphrase().encode(), default_backend())

# Get the raw bytes of the public key.
public_key_raw = private_key.public_key().public_bytes(Encoding.DER, PublicFormat.SubjectPublicKeyInfo)

# Get the sha256 hash of the raw bytes.
sha256hash = hashlib.sha256()
sha256hash.update(public_key_raw)

# Base64-encode the value and prepend the prefix 'SHA256:'.
public_key_fp = 'SHA256:' + base64.b64encode(sha256hash.digest()).decode('utf-8')
Copy

Java 示例

有关在 Java 中生成 JWT 的示例,请参阅 SimpleStatementsApi.java

备注

此示例仅供参考。请勿在生产应用程序或环境中使用此代码。

此示例使用以下第三方库:

  • ` Swagger Codegen <https://swagger.io/tools/swagger-codegen/download/ (https://swagger.io/tools/swagger-codegen/download/)>`_ :一个开源库,可用于开发 REST APIs 和应用程序。

  • ` Auth0 <https://auth0.com/docs/libraries (https://auth0.com/docs/libraries)>`_ :提供用于身份验证和生成 JWT 令牌的 Java APIs。

Node.js 示例

有关在 Node.js 中生成 JWT 的示例,请参阅 sql-api-generate-jwt.js

备注

此示例仅供参考。请勿在生产应用程序或环境中使用此代码。

语言: 中文