26个稳定版本
1.1.14 | 2022年9月23日 |
---|---|
1.1.12 | 2022年9月22日 |
1.1.5 | 2022年8月25日 |
1.1.3 | 2022年3月23日 |
#162 in HTTP服务器
71 每月下载次数
455KB
8K SLoC
具有用户管理、Kafka消息发布、S3上传/下载和Prometheus监控的Rust Rest API堆栈
默认安全的Rest API,使用hyper、tokio、bb8、kafka-threadpool、postgres和prometheus进行监控。
特性
- 用户管理和认证存储在postgres
- 异步s3上传和下载(从/到本地文件或从/到内存)
- 解耦的、异步的kafka线程池,使用环境变量连接到kafka集群,客户端mtls用于身份验证和传输加密
- 异步将所有成功用户事件发布到kafka主题(默认主题:
user.events
)和分区键(默认键:user-{user.id}
) - 使用自定义kafka主题、分区键和自定义头部的异步kafka消息传递,用于一次性消息。
概述
用户
- 支持使用存储在postgres中的一次性使用令牌重置用户密码和更改用户电子邮件。
- 用户可以上传和管理存储在AWS S3上的文件(假设在此Rust项目外部加载了有效的凭证)。
- 用户密码使用argon2进行散列。
认证
- 默认启用用户认证
- 包括在文档中的默认JWT签名密钥,用于根据需要构建新密钥。
数据库
- rest api服务器使用postgres和bb8客户端线程池。
- postgres数据库要求每个客户端连接包含postgres tls证书授权文件,以加密传输中的数据。
- 包含用于浏览器中数据库管理的 pgadmin (与 podman compose 部署)。
TLS 加密
- 包含一个用于构建自签名 TLS 资产的工具(包括您自己的私有证书颁发机构(CA))的 tls 资产生成器工具(./tls/create-tls-assets.sh)。
Ingress
组件 | 状态 |
---|---|
Rest API 服务器 | 监听tcp端口 3000 上的加密客户端连接 |
Postgres | 监听tcp端口 5432 上的加密客户端连接(需要 TLS 证书颁发机构) |
pgAdmin | 监听tcp端口 5433 上的加密 HTTP 客户端连接 |
入门
克隆存储库
git clone https://github.com/jay-johnson/restapi
cd restapi
使用 CFSSL 生成 TLS 资产和私有证书颁发机构(CA)
使用以下命令在 ./tls
目录下生成新的 TLS 资产
cd tls
./create-tls-assets.sh
cd ..
有关更多信息,请参阅 使用 CFSSL 生成 TLS 资产。
生成 JWT 私钥和公钥
使用以下命令在 ./jwt
目录下生成新的签名 JWT 键
cd jwt
./recreate-jwt.sh
cd ..
有关更多信息,请参阅 如何为 jsonwebtokens crate 构建JWT私钥和公钥。
使用 Podman 部署 Postgres 和 pgAdmin
有关更多信息,请参阅 构建和部署安全 Postgres 后端文档。
构建 API 服务器
cargo build --example server
运行 API 服务器
export RUST_BACKTRACE=1 && export RUST_LOG=info,kafka_threadpool=info && ./target/debug/examples/server
环境变量
Rest API
环境变量 | 默认值 |
---|---|
SERVER_NAME_API | api |
SERVER_NAME_LABEL | rust-restapi |
API_ENDPOINT | 0.0.0.0:3000 |
API_TLS_DIR | ./tls/api |
API_TLS_CA | ./tls/ca/ca.pem |
API_TLS_CERT | ./tls/api/server.pem |
API_TLS_KEY | ./tls/api/server-key.pem |
用户电子邮件验证
环境变量 | 默认值 |
---|---|
USER_EMAIL_VERIFICATION_REQUIRED | "0" |
USER_EMAIL_VERIFICATION_ENABLED | "1" |
USER_EMAIL_VERIFICATION_EXP_IN_SECONDS | "2592000" |
用户一次性密码验证码过期时间用于密码恢复
环境变量 | 默认值 |
---|---|
USER_OTP_EXP_IN_SECONDS | "2592000" |
Postgres 数据库
环境变量 | 默认值 |
---|---|
POSTGRES_USERNAME | datawriter |
POSTGRES_PASSWORD | "123321" |
POSTGRES_ENDPOINT | 0.0.0.0:5432 |
POSTGRES_TLS_DIR | ./tls/postgres |
POSTGRES_TLS_CA | ./tls/ca/ca.pem |
POSTGRES_TLS_CERT | ./tls/postgres/client.pem |
POSTGRES_TLS_KEY | ./tls/postgres/client-key.pem |
POSTGRES_DB_CONN_TYPE | postgresql |
Kafka 集群
有关更多信息,请参阅 kafka_threadpool 文档。
环境变量 | 目的 / 价值 |
---|---|
KAFKA_PUBLISH_EVENTS | 如果设置为 true 或 1 则将所有用户事件发布到 Kafka |
KAFKA_ENABLED | 使用: true 或 1 切换 kafka_threadpool 开启,否则禁用 threadpool |
KAFKA_LOG_LABEL | 出现在所有 crate 日志中的跟踪标签 |
KAFKA_BROKERS | 由逗号分隔的代理列表(host1:port,host2:port,host3:port ) |
KAFKA_TOPICS | 由逗号分隔的支持主题列表 |
KAFKA_PUBLISH_RETRY_INTERVAL_SEC | 在每次发布重试前休眠的秒数 |
KAFKA_PUBLISH_IDLE_INTERVAL_SEC | 如果没有消息要处理,休眠的秒数 |
KAFKA_NUM_THREADS | threadpool 的线程数 |
KAFKA_TLS_CLIENT_KEY | 可选 - Kafka mTLS密钥的路径(./tls/kafka-cluster-0/client-key.pem) |
KAFKA_TLS_CLIENT_CERT | 可选 - Kafka mTLS证书的路径(./tls/kafka-cluster-0/client.pem) |
KAFKA_TLS_CLIENT_CA | 可选 - Kafka mTLS证书颁发机构(CA)的路径(./tls/ca/ca.pem) |
KAFKA_METADATA_COUNT_MSG_OFFSETS | 可选 - 设置为除true 以外的任何值以跳过偏移量的计数 |
示例kafka.env文件
# enable the cluster
export KAFKA_ENABLED=1
export KAFKA_LOG_LABEL="ktp"
export KAFKA_BROKERS="host1:port,host2:port,host3:port"
export KAFKA_TOPICS="testing"
export KAFKA_PUBLISH_RETRY_INTERVAL_SEC="1.0"
export KAFKA_NUM_THREADS="5"
export KAFKA_TLS_CLIENT_CA="./tls/ca/ca.pem"
export KAFKA_TLS_CLIENT_CERT="./tls/kafka-cluster-0/client.pem"
export KAFKA_TLS_CLIENT_KEY="./tls/kafka-cluster-0/client-key.pem"
# the KafkaPublisher can count the offsets for each topic with "true" or "1"
export KAFKA_METADATA_COUNT_MSG_OFFSETS="true"
S3
环境变量 | 默认值 |
---|---|
S3_DATA_BUCKET | YOUR_BUCKET |
S3_DATA_PREFIX | /rust-restapi/tests |
S3_STORAGE_CLASS | STANDARD |
S3_DATA_UPLOAD_TO_S3 | "0" |
JWT
环境变量 | 默认值 |
---|---|
TOKEN_EXPIRATION_SECONDS_INTO_FUTURE | "2592000" |
TOKEN_ORG | example.org |
TOKEN_HEADER | Bearer |
TOKEN_ALGO_PRIVATE_KEY | ./jwt/private-key-pkcs8.pem |
TOKEN_ALGO_PUBLIC_KEY | ./jwt/public-key.pem |
SERVER_PKI_DIR_JWT | ./jwt |
SERVER_PASSWORD_SALT | 78197b60-c950-4339-a52c-053165a04764 |
Rust
环境变量 | 默认值 |
---|---|
RUST_BACKTRACE | "1" |
RUST_LOG | info |
Debug
环境变量 | 默认值 |
---|---|
DEBUG | "1" |
Docker构建
构建基础镜像
这将使用podman构建一个初始基础镜像。注意:此基础镜像在不同的CPU芯片组上无法工作,因为openssl库是为此基础镜像在镜像内部编译的。
./build-base.sh
构建衍生镜像
通过重用基础镜像,此衍生镜像只需要重新编译服务器。通过最小程度的代码更改,这比基础镜像构建快得多。
./build-derived.sh
Kubernetes
启动Kafka
如果您没有运行的Kafka集群,您可以使用以下方法部署自己的集群
https://github.com/jay-johnson/rust-with-strimzi-kafka-and-tls
Helm图表
将TLS资产部署到Kubernetes
此命令将部署所有jwt密钥、tls资产和凭证到dev
命名空间
./deploy-kubernetes-assets.sh -e dev
将Rust Rest API部署到Kubernetes
有关将示例helm图表部署到kubernetes集群的说明,请参阅部署Rust Rest API helm图表到kubernetes指南。
默认情况下,这使用jayjohnson/rust-restapi
容器镜像
helm upgrade --install -n dev dev-api ./charts/rust-restapi -f ./charts/rust-restapi/values.yaml
监控
Prometheus
本节假设您已经在kubernetes内部运行了一个有效的Prometheus实例。以下是用于监控kubernetes内部rest api部署副本的Prometheus scrape_config
。注意,此配置还假设api图表在dev
命名空间中运行。
scrape_configs:
- job_name: rust-restapi
scrape_interval: 10s
scrape_timeout: 5s
metrics_path: /metrics
scheme: https
tls_config:
insecure_skip_verify: true
static_configs:
- targets:
- dev-api.dev.svc.cluster.local:3000
支持的API
以下是每个基于url的Request
和Response
支持的json合约。每个客户端请求都由./src/handle_requests.rs模块处理,并作为响应返回给客户端(使用serde_json
进行序列化)。
用户API
创建用户
为新用户创建单个users
记录
- URL路径:
/user
- 方法:
POST
- 处理器:create_user
- 请求:ApiReqUserCreate
- 响应:ApiResUserCreate
更新用户
更新支持的users
字段(包括更改用户电子邮件和密码)
- URL路径:
/user
- 方法:
PUT
- 处理器:update_user
- 请求:ApiReqUserUpdate
- 响应:ApiResUserUpdate
获取用户
通过 users.id
获取单个用户 - 默认情况下,用户只能获取自己的账户详情
- URL路径:
/user/USERID
- 方法:
GET
- 处理程序: get_user
- 请求: ApiReqUserGet
- 响应: ApiResUserGet
删除用户
删除单个 users
记录(注意:这不会删除数据库记录,只是将 users.state
设置为非活动状态 1
)
- URL路径:
/user
- 方法:
DELETE
- 处理程序: delete_user
- 请求: ApiReqUserDelete
- 响应: ApiResUserDelete
在数据库中搜索用户
在数据库中搜索匹配的 users
记录
- URL路径:
/user/search
- 方法:
POST
- 处理程序: search_users
- 请求: ApiReqUserSearch
- 响应: ApiResUserSearch
创建一次性密码重置令牌(OTP)
创建一个一次性使用的密码重置令牌,允许用户通过出示令牌来更改其 users.password
值
- URL路径:
/user/password/reset
- 方法:
POST
- 处理程序: create_otp
- 请求: ApiReqUserCreateOtp
- 响应: ApiResUserCreateOtp
消耗一次性密码重置令牌(OTP)
消耗一次性密码并更改用户的 users.password
值为新 argon2-hashed 密码
- URL路径:
/user/password/change
- 方法:
POST
- 处理程序: consume_user_otp
- 请求: ApiReqUserConsumeOtp
- 响应: ApiResUserConsumeOtp
验证用户的电子邮件
消耗一次性验证令牌并更改用户的 users.verified
值为已验证(1
)
- URL路径:
/user/verify
- 方法:
GET
- 处理程序: verify_user
- 请求: ApiReqUserVerify
- 响应: ApiResUserVerify
用户S3 API
将文件异步上传到AWS S3并在数据库中存储跟踪记录
将磁盘上的本地文件异步上传到AWS S3并在 users_data
表中存储跟踪记录。文档称这为 user data
或 user data file
记录。
- URL路径:
/user/data
- 方法:
POST
- 处理程序: upload_user_data
- 请求: ApiReqUserUploadData
- 响应: ApiResUserUploadData
更新存储在AWS S3中的现有用户数据文件记录
更新存在于AWS S3中的文件的users_data
跟踪记录
- URL路径:
/user/data
- 方法:
PUT
- 处理器: update_user_data
- 请求: ApiReqUserUpdateData
- 响应: ApiResUserUpdateData
从数据库中搜索现有用户数据文件
根据请求的值在users_data
数据库中搜索匹配的记录
- URL路径:
/user/data/search
- 方法:
POST
- 处理器: search_user_data
- 请求: ApiReqUserSearchData
- 响应: ApiResUserSearchData
用户身份验证API
用户登录
登录用户并获取用于后续客户端请求身份验证的JSON Web Token (JWT)
- URL路径:
/login
- 方法:
POST
- 处理器: login
- 请求: ApiReqUserLogin
- 响应: ApiResUserLogin
集成测试
本项目专注于v1版本的集成测试,而不是仅限于Rust测试(具体来说,所有内容都使用curl进行了测试)
Podman镜像推送
cur_tag=$(cat Cargo.toml | grep version | head -1 | sed -e 's/"//g' | awk '{print $NF}')
podman tag IMAGE_ID "docker://docker.io/jayjohnson/rust-restapi:${cur_tag}"
podman tag IMAGE_ID "docker://docker.io/jayjohnson/rust-restapi:latest"
podman push "docker.io/jayjohnson/rust-restapi:${cur_tag}"
podman push "docker.io/jayjohnson/rust-restapi:latest"
构建文档
cargo doc --example server
启动开发服务器
source ./env/api.env && source ./env/kafka.env && source ./env/postgres.env && cargo build --example server && export RUST_BACKTRACE=1 && export RUST_LOG=info,kafka_threadpool=info,rdkafka=error && ./target/debug/examples/server
依赖项
~40–58MB
~1M SLoC