手机APP研发中的用户授权架构设计:使用 Rust 语言实现(基于 RSA 和 Salvo)

文摘   2024-11-05 00:11   北京  

引言

在手机APP研发中,用户授权是确保应用安全性和用户体验的关键环节。本文将详细介绍如何使用 Rust 语言设计和实现一个用户授权架构,涵盖 JWT 生成、验证、密钥管理、HTTPS 加密传输、短有效期、二次加密、黑名单机制和监控日志等安全规避策略。我们将使用rsacrate 0.9.6 处理 RSA 密钥,使用salvo0.74 作为 Web 框架,并使用 PKCS8 格式的证书。

架构设计

1. 用户授权流程

  1. 用户登录:用户输入用户名和密码,前端发送登录请求到后端。
  2. JWT 生成:后端验证用户身份后,生成 JWT。
  3. JWT 返回:后端将 JWT 返回给前端。
  4. JWT 存储:前端将 JWT 存储在本地(如 LocalStorage 或 Secure Cookie)。
  5. JWT 验证:前端在每次请求时,将 JWT 附加在请求头中,后端验证 JWT 的签名和有效期。

2. 技术栈

  • Rust:后端开发语言。
  • Salvo:Rust 的 Web 框架。
  • jsonwebtoken:Rust 的 JWT 库。
  • rsa:Rust 的 RSA 库,用于生成和管理密钥对。
  • serde:Rust 的序列化和反序列化库。
  • tokio:Rust 的异步运行时。

实战代码

1. 项目结构

user-auth-app/
├── Cargo.toml
├── src/
│ ├── main.rs
│ ├── auth.rs
│ ├── jwt.rs
│ ├── key_manager.rs
│ ├── blacklist.rs
│ └── logger.rs
└── .env

2. Cargo.toml

[package]
name = "user-auth-app"
version = "0.1.0"
edition = "2021"

[dependencies]
salvo = "0.74"
jsonwebtoken = "9"
rsa = "0.9.6"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }
dotenv = "0.15"
chrono = "0.4"
log = "0.4"
env_logger = "0.9"

3. main.rs

use salvo::prelude::*;
use dotenv::dotenv;
use std::env;

mod auth;
mod jwt;
mod key_manager;
mod blacklist;
mod logger;

#[tokio::main]
async fn main() {
    dotenv().ok();
    logger::init();

    let key_manager = key_manager::KeyManager::new();
    let blacklist = blacklist::Blacklist::new();

    let router = Router::new()
        .push(Router::with_path("login").post(auth::login))
        .push(Router::with_path("protected").get(auth::protected));

    let server = Server::new(router)
        .bind("127.0.0.1:8080")
        .await
        .unwrap();

    server.run().await;
}

4. auth.rs

use salvo::prelude::*;
use serde::{Deserialize, Serialize};
use crate::jwt::{Claims, encode_jwt, decode_jwt};
use crate::key_manager::KeyManager;
use crate::blacklist::Blacklist;

#[derive(Deserialize)]
struct LoginRequest {
    username: String,
    password: String,
}

#[derive(Serialize)]
struct LoginResponse {
    token: String,
}

pub async fn login(
    req: &mut Request,
    depot: &mut Depot,
    res: &mut Response,
) {
    let key_manager = depot.obtain::<KeyManager>().unwrap();
    let login_req: LoginRequest = req.parse_json().await.unwrap();

    // 模拟用户验证
    if login_req.username == "user" && login_req.password == "password" {
        let claims = Claims {
            sub: login_req.username.clone(),
            exp: chrono::Utc::now() + chrono::Duration::minutes(15),
        };
        let token = encode_jwt(&claims, &key_manager.get_private_key()).unwrap();
        res.render(Json(LoginResponse { token }));
    } else {
        res.status_code(StatusCode::UNAUTHORIZED);
    }
}

pub async fn protected(
    req: &mut Request,
    depot: &mut Depot,
    res: &mut Response,
) {
    let key_manager = depot.obtain::<KeyManager>().unwrap();
    let blacklist = depot.obtain::<Blacklist>().unwrap();

    if let Some(token) = req.header("Authorization") {
        let token = token.replace("Bearer """);
        if blacklist.contains(&token).await {
            res.status_code(StatusCode::UNAUTHORIZED);
            return;
        }
        match decode_jwt(&token, &key_manager.get_public_key()) {
            Ok(claims) => res.render(Json(claims)),
            Err(_) => res.status_code(StatusCode::UNAUTHORIZED),
        }
    } else {
        res.status_code(StatusCode::UNAUTHORIZED);
    }
}

5. jwt.rs

use jsonwebtoken::{encode, decode, Header, EncodingKey, DecodingKey, Validation, errors::Error};
use serde::{Deserialize, Serialize};
use chrono::{DateTime, Utc};

#[derive(Debug, Serialize, Deserialize)]
pub struct Claims {
    pub sub: String,
    pub exp: DateTime<Utc>,
}

pub fn encode_jwt(claims: &Claims, private_key: &[u8]) -> Result<String, Error> {
    encode(&Header::default(), claims, &EncodingKey::from_rsa_pem(private_key)?)
}

pub fn decode_jwt(token: &str, public_key: &[u8]) -> Result<Claims, Error> {
    decode::<Claims>(token, &DecodingKey::from_rsa_pem(public_key)?, &Validation::default())
        .map(|data| data.claims)
}

6. key_manager.rs

use rsa::{RsaPrivateKey, RsaPublicKey, pkcs8::{EncodePublicKey, LineEnding}};
use std::sync::Arc;
use tokio::sync::RwLock;

#[derive(Clone)]
pub struct KeyManager {
    private_key: Arc<RwLock<Vec<u8>>>,
    public_key: Arc<RwLock<Vec<u8>>>,
}

impl KeyManager {
    pub fn new() -> Self {
        let mut rng = rand::thread_rng();
        let bits = 2048;
        let private_key = RsaPrivateKey::new(&mut rng, bits).expect("failed to generate a key");
        let public_key = RsaPublicKey::from(&private_key);

        let private_key_pem = private_key.to_pkcs8_pem(LineEnding::LF).unwrap();
        let public_key_pem = public_key.to_public_key_pem(LineEnding::LF).unwrap();

        Self {
            private_key: Arc::new(RwLock::new(private_key_pem.as_bytes().to_vec())),
            public_key: Arc::new(RwLock::new(public_key_pem.as_bytes().to_vec())),
        }
    }

    pub async fn get_private_key(&self) -> Vec<u8> {
        self.private_key.read().await.clone()
    }

    pub async fn get_public_key(&self) -> Vec<u8> {
        self.public_key.read().await.clone()
    }
}

7. blacklist.rs

use std::collections::HashSet;
use std::sync::Arc;
use tokio::sync::RwLock;

#[derive(Clone)]
pub struct Blacklist {
    tokens: Arc<RwLock<HashSet<String>>>,
}

impl Blacklist {
    pub fn new() -> Self {
        Self {
            tokens: Arc::new(RwLock::new(HashSet::new())),
        }
    }

    pub async fn add(&self, token: &str) {
        self.tokens.write().await.insert(token.to_string());
    }

    pub async fn contains(&self, token: &str) -> bool {
        self.tokens.read().await.contains(token)
    }
}

8. logger.rs

use log::{info, error};
use env_logger::Env;

pub fn init() {
    env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
    info!("Logger initialized");
}

9. .env

RUST_LOG=info

总结

本文详细介绍了如何在手机APP研发中使用 Rust 语言设计和实现一个用户授权架构。通过使用 Salvo、jsonwebtoken、rsa 等库,实现了 JWT 生成、验证、密钥管理、HTTPS 加密传输、短有效期、二次加密、黑名单机制和监控日志等安全规避策略。实战代码展示了如何构建一个安全可靠的用户授权系统,确保用户数据的安全和隐私。


无论身在何处

有我不再孤单孤单

长按识别二维码关注我们




育儿之家 YEZJ
“Rust编程之道”,带你探索Rust语言之美,精进编程技艺,开启无限可能!🦀🦀🦀
 最新文章