🎯

rust-auth

🎯Skill

from huiali/rust-skills

VibeIndex|
What it does

Enables robust JWT, API Key, and distributed token authentication with secure password storage in Rust.

📦

Part of

huiali/rust-skills(30 items)

rust-auth

Installation

📋 No install commands found in docs. Showing default command. Check GitHub for actual instructions.
Quick InstallInstall with npx
npx skills add huiali/rust-skills --skill rust-auth
3Installs
-
AddedFeb 4, 2026

Skill Details

SKILL.md

"JWT 认证、API Key 认证、分布式 Token 存储、密码安全存储"

Overview

# Rust Auth - 认证授权技能

> 本技能提供完整的认证授权解决方案,包括 JWT、API Key、分布式 Token 存储等模式。

核心概念

1. 认证架构设计

```

认证授权架构

├── 认证层 (Authentication)

│ ├── JWT 认证

│ ├── API Key 认证

│ └── 多因素认证

├── 授权层 (Authorization)

│ ├── 基于角色的访问控制 (RBAC)

│ ├── 基于权限的访问控制

│ └── 细粒度权限

└── 会话管理

├── Token 管理

├── Session 存储

└── 并发控制

```

2. 认证方式对比

| 认证方式 | 适用场景 | 安全性 | 实现复杂度 |

|---------|---------|--------|----------|

| JWT Token | 前后端分离、API 访问 | 高 | 中 |

| API Key | 服务间调用、自动化脚本 | 中 | 低 |

| 双因素 | 高安全要求场景 | 极高 | 高 |

---

核心模式

1. JWT Token 认证

```rust

//! JWT 认证模块

use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};

use serde::{Deserialize, Serialize};

use std::time::{Duration, SystemTime};

use thiserror::Error;

/// JWT 错误类型

#[derive(Error, Debug)]

pub enum JwtError {

#[error("Token 解析失败: {0}")]

ParseError(String),

#[error("Token 验证失败: {0}")]

ValidationError(String),

#[error("Token 已过期")]

Expired,

#[error("Token 签名无效")]

InvalidSignature,

}

/// Token 声明(通用结构)

#[derive(Debug, Serialize, Deserialize)]

pub struct Claims {

pub sub: String, // 主体标识

pub name: Option, // 名称

pub roles: Vec, // 角色列表

pub exp: u64, // 过期时间

pub iat: u64, // 签发时间

// 业务字段可通过扩展字段添加

}

/// JWT 服务

pub struct JwtService {

encoding_key: EncodingKey,

decoding_key: DecodingKey,

secret: String,

expiry: Duration,

algorithm: Algorithm,

}

impl JwtService {

pub fn new(secret: String, expiry_seconds: u64) -> Self {

Self {

encoding_key: EncodingKey::from_secret(secret.as_bytes()),

decoding_key: DecodingKey::from_secret(secret.as_bytes()),

secret,

expiry: Duration::from_secs(expiry_seconds),

algorithm: Algorithm::HS256,

}

}

/// 生成 Token

pub fn generate_token(&self, subject: &str, roles: &[String]) -> Result {

let now = SystemTime::now()

.duration_since(SystemTime::UNIX_EPOCH)

.unwrap()

.as_secs();

let claims = Claims {

sub: subject.to_string(),

name: None,

roles: roles.to_vec(),

exp: now + self.expiry.as_secs(),

iat: now,

};

encode(&Header::new(self.algorithm), &claims, &self.encoding_key)

.map_err(|e| JwtError::ParseError(e.to_string()))

}

/// 验证并解析 Token

pub fn verify_token(&self, token: &str) -> Result {

let validation = Validation::new(self.algorithm);

decode::(token, &self.decoding_key, &validation)

.map(|data| data.claims)

.map_err(|e| match e.kind() {

jsonwebtoken::errors::ErrorKind::ExpiredSignature => JwtError::Expired,

jsonwebtoken::errors::ErrorKind::InvalidSignature => JwtError::InvalidSignature,

_ => JwtError::ValidationError(e.to_string()),

})

}

/// 检查 Token 是否即将过期(剩余 < 10 分钟返回 true)

pub fn is_expiring_soon(&self, claims: &Claims) -> bool {

let now = SystemTime::now()

.duration_since(SystemTime::UNIX_EPOCH)

.unwrap()

.as_secs();

claims.exp - now < 600

}

}

```

2. API Key 认证

```rust

//! API Key 认证模块

use chrono::{DateTime, Utc};

use serde::{Deserialize, Serialize};

use sha2::{Digest, Sha256};

/// API Key 配置

#[derive(Debug, Clone)]

pub struct ApiKeyConfig {

pub prefix: String, // Key 前缀

pub secret: String, // 签名密钥

pub expiry_days: i64, // 有效期

pub allowed_ips: Vec, // IP 白名单

}

/// API Key 信息

#[derive(Debug, Clone, Serialize, Deserialize)]

pub struct ApiKeyInfo {

pub key_id: String,

pub owner_id: String,

pub secret_hash: String,

pub created_at: DateTime,

pub expires_at: DateTime,

pub last_used_at: Option>,

pub disabled: bool,

pub scopes: Vec,

}

/// API Key 错误

#[derive(Debug)]

pub enum ApiKeyError {

InvalidKey,

KeyExpired,

KeyRevoked,

SignatureMismatch,

}

/// API Key 生成器

pub struct ApiKeyGenerator;

impl ApiKeyGenerator {

/// 生成 API Key

/// 格式: {prefix}_{key_id}_{signature}

pub fn generate(config: &ApiKeyConfig, owner_id: &str) -> (String, String) {

let key_id = Self::generate_key_id();

let secret = Self::generate_secret();

let signature = Self::compute_signature(config, &key_id, &secret);

let api_key = format!("{}_{}_{}", config.prefix, key_id, signature);

let secret_hash = Self::hash_secret(config, &secret);

(api_key, secret_hash)

}

/// 验证 API Key

pub async fn verify(

config: &ApiKeyConfig,

api_key: &str,

ip: Option<&str>,

key_info: &ApiKeyInfo,

) -> Result<(), ApiKeyError> {

let parts: Vec<&str> = api_key.split('_').collect();

if parts.len() != 3 {

return Err(ApiKeyError::InvalidKey);

}

if key_info.disabled {

return Err(ApiKeyError::KeyRevoked);

}

if key_info.expires_at < Utc::now() {

return Err(ApiKeyError::KeyExpired);

}

if let Some(client_ip) = ip {

if !config.allowed_ips.is_empty()

&& !config.allowed_ips.contains(&client_ip.to_string()) {

return Err(ApiKeyError::InvalidKey);

}

}

let expected_signature = Self::compute_signature(config, parts[1], "stored");

if parts[2] != expected_signature {

return Err(ApiKeyError::SignatureMismatch);

}

Ok(())

}

fn generate_key_id() -> String {

use rand::Rng;

const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyz0123456789";

let mut rng = rand::thread_rng();

(0..16).map(|_| CHARSET[rng.gen_range(0..CHARSET.len())] as char).collect()

}

fn generate_secret() -> String {

use rand::Rng;

const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";

let mut rng = rand::thread_rng();

(0..32).map(|_| CHARSET[rng.gen_range(0..CHARSET.len())] as char).collect()

}

fn compute_signature(config: &ApiKeyConfig, key_id: &str, secret: &str) -> String {

let data = format!("{}{}", key_id, secret);

let mut hasher = Sha256::new();

hasher.update(data.as_bytes());

hasher.update(config.secret.as_bytes());

format!("{:x}", hasher.finalize())[..8].to_string()

}

fn hash_secret(config: &ApiKeyConfig, secret: &str) -> String {

let mut hasher = Sha256::new();

hasher.update(secret.as_bytes());

hasher.update(config.secret.as_bytes());

format!("{:x}", hasher.finalize())

}

}

```

3. 分布式 Token 存储

```rust

//! 分布式 Token 存储

use redis::AsyncCommands;

/// Token 存储配置

#[derive(Debug, Clone)]

pub struct TokenStoreConfig {

pub redis_url: String,

pub prefix: String,

}

pub struct TokenStore {

redis: Option,

config: TokenStoreConfig,

}

impl TokenStore {

pub async fn new(config: TokenStoreConfig) -> Result> {

let redis = if config.redis_url.starts_with("redis://") {

let client = redis::Client::open(config.redis_url.as_str())?;

let conn = redis::aio::ConnectionManager::new(client).await?;

Some(conn)

} else {

None

};

Ok(Self { redis, config })

}

/// 存储 Token(带并发控制)

pub async fn store_token(

&self,

user_id: &str,

token_id: &str,

claims: &Claims,

max_concurrent: usize,

) -> Result<(), Box> {

if let Some(ref mut redis) = self.redis {

let prefix = &self.config.prefix;

let key = format!("{}:tokens:{}", prefix, user_id);

// 检查并发数量

let current_count: usize = redis.scard(&key).await?;

if current_count >= max_concurrent {

if let Some(old_token) = redis.spop::(&key).await? {

redis.del(&format!("{}:token:{}", prefix, old_token)).await?;

}

}

let token_key = format!("{}:token:{}", prefix, token_id);

let token_data = serde_json::to_string(claims)?;

let ttl = claims.exp.saturating_sub(86400);

redis.set_ex(&token_key, token_data, ttl).await?;

redis.sadd(&key, token_id).await?;

}

Ok(())

}

/// 撤销 Token

pub async fn revoke_token(&self, user_id: &str, token_id: &str) -> Result<(), Box> {

if let Some(ref mut redis) = self.redis {

let prefix = &self.config.prefix;

redis.del(&format!("{}:token:{}", prefix, token_id)).await?;

redis.srem(&format!("{}:tokens:{}", prefix, user_id), token_id).await?;

}

Ok(())

}

/// 撤销用户所有 Token

pub async fn revoke_all_tokens(&self, user_id: &str) -> Result<(), Box> {

if let Some(ref mut redis) = self.redis {

let prefix = &self.config.prefix;

let set_key = format!("{}:tokens:{}", prefix, user_id);

let token_ids: Vec = redis.smembers(&set_key).await?;

for token_id in token_ids {

redis.del(&format!("{}:token:{}", prefix, token_id)).await?;

}

redis.del(&set_key).await?;

}

Ok(())

}

}

```

---

最佳实践

1. 认证中间件

```rust

//! 认证中间件

use actix_web::{

dev::{forward_ready, Service, ServiceRequest, ServiceResponse, Transform},

Error, HttpMessage,

};

use futures::future::{ready, LocalBoxFuture, Ready};

use std::rc::Rc;

pub struct JwtAuthentication;

impl Transform for JwtAuthentication

where

S: Service, Error = Error> + 'static,

S::Future: 'static,

B: 'static,

{

type Response = ServiceResponse;

type Error = Error;

type InitError = ();

type Transform = JwtAuthMiddleware;

type Future = Ready>;

fn new_transform(&self, service: S) -> Self::Future {

ready(Ok(JwtAuthMiddleware { service: Rc::new(service) }))

}

}

pub struct JwtAuthMiddleware {

service: Rc,

}

impl Service for JwtAuthMiddleware

where

S: Service, Error = Error> + 'static,

S::Future: 'static,

B: 'static,

{

type Response = ServiceResponse;

type Error = Error;

type Future = LocalBoxFuture<'static, Result>;

forward_ready!(service);

fn call(&self, req: ServiceRequest) -> Self::Future {

let service = Rc::clone(&self.service);

Box::pin(async move {

let auth_header = req.headers()

.get("Authorization")

.and_then(|v| v.to_str().ok());

let token = match auth_header {

Some(header) if header.starts_with("Bearer ") => &header[7..],

_ => return Err(actix_web::error::ErrorUnauthorized("Invalid Authorization")),

};

let jwt_service = req.app_data::()

.ok_or(actix_web::error::ErrorInternalServerError("JWT not configured"))?;

let claims = jwt_service.verify_token(token)

.map_err(|_| actix_web::error::ErrorUnauthorized("Invalid token"))?;

req.extensions_mut().insert(claims);

service.call(req).await

})

}

}

```

2. 密码安全存储

```rust

//! 密码安全存储

use argon2::{self, Config};

use rand::Rng;

/// 密码哈希服务

pub struct PasswordHasher;

impl PasswordHasher {

/// 哈希密码

pub fn hash_password(password: &str) -> Result {

let salt = rand::thread_rng().gen::<[u8; 32]>();

let config = Config::default();

argon2::hash_raw(password.as_bytes(), &salt, &config)

.map(|bytes| {

let salt_b64 = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &salt);

let hash_b64 = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, &bytes);

format!("$argon2id$v=19,m=4096,t=3,p=1${}${}$", salt_b64, hash_b64)

})

}

/// 验证密码

pub fn verify_password(password: &str, stored_hash: &str) -> Result {

use subtle::ConstantTimeEq;

let parts: Vec<&str> = stored_hash.split('$').collect();

if parts.len() != 5 { return Ok(false); }

let salt = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, parts[2]).unwrap_or_default();

let stored = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, parts[3]).unwrap_or_default();

let config = Config::default();

let computed = argon2::hash_raw(password.as_bytes(), &salt, &config)?;

Ok(computed.as_slice().ct_eq(&stored))

}

}

```

---

常见问题排查

| 问题 | 原因 | 解决方案 |

|-----|------|---------|

| Token 过期 | 时间窗口问题 | 刷新 token |

| 并发登录异常 | Redis 连接 | 检查连接池 |

| API Key 盗用 | 未配置 IP 白名单 | 启用 IP 限制 |

| 密码验证慢 | Argon2 耗时 | 调整工作因子 |

---

关联技能

  • rust-web - Web 开发框架集成
  • rust-middleware - 中间件设计
  • rust-error - 错误处理
  • rust-cache - Token 存储

More from this repository10

🎯
rust-skill🎯Skill

Provides expert Rust programming assistance, solving compilation errors, ownership, lifetimes, concurrency, and performance optimization challenges.

🎯
rust-skill-index🎯Skill

Indexes and provides quick navigation for 35 Rust skills across core, advanced, and expert categories.

🎯
rust-error🎯Skill

Expertly handles Rust error scenarios by providing comprehensive guidance on Result, Option, error types, propagation, and panic strategies.

🎯
rust-async🎯Skill

Handles advanced Rust async patterns like Stream processing, backpressure, select, cancellation, and concurrency management with Tokio.

🎯
rust-concurrency🎯Skill

Expertly handles Rust concurrency challenges by safely managing threads, async operations, and preventing race conditions and deadlocks.

🎯
rust-anti-pattern🎯Skill

Identifies and helps refactor Rust anti-patterns like unnecessary cloning, unwrapping, and inefficient iterations to improve code quality.

🎯
rust-web🎯Skill

Builds robust Rust web services using frameworks like axum and actix, handling routing, database interactions, and API design with type-safe, performant code.

🎯
rust-ownership🎯Skill

Skill

🎯
rust-zero-cost🎯Skill

Analyzes and optimizes Rust generic abstractions and dispatch strategies for zero-cost performance and compile-time flexibility.

🎯
rust-mutability🎯Skill

Expertly manages Rust mutability challenges, resolving borrowing conflicts and providing safe interior mutability strategies across different contexts.