构建安全的移动应用登录及API接口授权系统:Rust与Salvo实战指南

文摘   2024-11-07 00:16   北京  

引言

在现代移动应用中,用户登录和API接口的授权处理是至关重要的安全环节。本文将详细介绍如何使用Rust和Salvo框架构建一个安全的移动应用登录及API接口授权系统。我们将涵盖前端和后端的处理流程,并提供详细的示例代码和文字说明。

1. 系统架构概述

本方案设计一个基于JWT(JSON Web Token)的鉴权系统,确保用户登录信息长期有效,并提供安全的接口交互。

技术栈

  • 前端: 移动应用(iOS/Android)
  • 后端: Rust + Salvo 0.74.1
  • 数据库: PostgreSQL/MySQL
  • 缓存: Redis
  • 加密: JWT (JSON Web Token)

2. 用户登录流程

  1. 用户登录: 用户在移动应用中输入用户名和密码。
  2. 前端请求: 前端将用户名和密码通过HTTPS发送到后端。
  3. 后端验证: 后端验证用户名和密码,生成JWT并返回给前端。
  4. 前端存储: 前端存储JWT,并在每次请求时将其附加到请求头中。

3. Cargo.toml 内容

Cargo.toml文件中,我们需要添加必要的依赖项,以便使用 Salvo 框架和 JWT 库。

[package]
name = "your_project_name"
version = "0.1.0"
edition = "2021"

[dependencies]
salvo = "0.74.1"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
jsonwebtoken = "9.3"
tokio = { version = "1", features = ["full"] }
chrono = "0.4"

[dependencies.sqlx]
version = "0.5"
features = ["postgres", "runtime-tokio-native-tls"]

[dependencies.redis]
version = "0.21"

[dependencies.dotenv]
version = "0.15"

4. 后端接口设计

4.1 登录接口

首先,我们需要定义一个登录接口,用于验证用户名和密码,并生成JWT。

use salvo::prelude::*;
use salvo::http::StatusCode;
use serde::{Deserialize, Serialize};
use jsonwebtoken::{encode, Header, EncodingKey, decode, DecodingKey, Validation, errors::Error};
use std::time::{SystemTime, UNIX_EPOCH, Duration};

#[derive(Debug, Serialize, Deserialize)]
struct Claims {
    sub: String,
    exp: u64,
}

#[handler]
async fn login(req: &mut Request, res: &mut Response) {
    let username = req.form_value("username").unwrap();
    let password = req.form_value("password").unwrap();

    // 验证用户名和密码
    if let Some(user) = db::find_user_by_username_and_password(username, password).await {
        // 生成 JWT
        let token = generate_jwt(&user);
        res.render(Json(json!({ "token": token })));
    } else {
        res.status_code(StatusCode::UNAUTHORIZED);
    }
}

fn generate_jwt(user: &User) -> String {
    let claims = Claims {
        sub: user.id.to_string(),
        exp: (SystemTime::now() + Duration::from_secs(3600)).duration_since(UNIX_EPOCH).unwrap().as_secs(),
    };
    encode(&Header::default(), &claims, &EncodingKey::from_secret("secret".as_ref())).unwrap()
}

4.2 验证 JWT

在每个需要授权的接口中,我们需要验证JWT的有效性。

#[handler]
async fn protected_route(req: &mut Request, res: &mut Response) {
    let token = req.header("Authorization").unwrap().split_whitespace().nth(1).unwrap();
    let claims = decode::<Claims>(token, &DecodingKey::from_secret("secret".as_ref()), &Validation::default()).unwrap().claims;

    // 验证通过,继续处理请求
    // ...
}

5. 前端处理

5.1 存储 JWT

前端可以使用SecureStore(iOS)或SharedPreferences(Android)来安全地存储JWT。

// iOS (Swift)
UserDefaults.standard.set(token, forKey: "authToken")

// Android (Kotlin)
val sharedPreferences = getSharedPreferences("app_prefs"Context.MODE_PRIVATE)
sharedPreferences.edit().putString("authToken", token).apply()

5.2 发送 JWT

每次请求时,前端需要将JWT附加到请求头中。

// iOS (Swift)
let headers = ["Authorization""Bearer \(token)"]
let request = URLRequest(url: url)
request.allHTTPHeaderFields = headers

// Android (Kotlin)
val request = Request.Builder()
    .url(url)
    .header("Authorization""Bearer $token")
    .build()

6. 长期有效登录

6.1 刷新 JWT

为了保证登录信息长期有效,可以设计一个刷新机制:

  • JWT 有效期: 设置较短的有效期(例如 1 小时)。
  • 刷新接口: 提供一个刷新接口,前端在JWT即将过期时调用该接口获取新的JWT。
#[handler]
async fn refresh_token(req: &mut Request, res: &mut Response) {
    let token = req.header("Authorization").unwrap().split_whitespace().nth(1).unwrap();
    let claims = decode::<Claims>(token, &DecodingKey::from_secret("secret".as_ref()), &Validation::default()).unwrap().claims;

    // 验证通过,生成新的 JWT
    let new_token = generate_jwt(&db::find_user_by_id(claims.sub).await.unwrap());
    res.render(Json(json!({ "token": new_token })));
}

6.2 前端自动刷新

前端可以在JWT即将过期时自动调用刷新接口,确保用户不会因为JWT过期而被迫重新登录。

// iOS (Swift)
func refreshTokenIfNeeded() {
    if let token = UserDefaults.standard.string(forKey: "authToken"), let claims = decodeJWT(token) {
        let expirationTime = claims.exp
        if expirationTime - Date().timeIntervalSince1970 < 60 { // 提前 60 秒刷新
            refreshToken()
        }
    }
}

func refreshToken() {
    // 调用刷新接口
}

7. 安全性考虑

  • HTTPS: 所有接口必须通过HTTPS传输。
  • JWT 加密: 使用强加密算法(如 HS256)加密JWT。
  • 防止重放攻击: 在JWT中包含时间戳或nonce,并在后端验证。
  • 限流: 对登录和刷新接口进行限流,防止暴力破解。

8. 总结

通过使用JWT和自动刷新机制,我们确保了用户登录信息长期有效。前端负责存储和发送JWT,后端负责验证和生成JWT。通过合理的接口设计和安全性考虑,我们构建了一个安全且高效的移动应用登录及API接口授权系统。

希望这篇教程能够帮助你构建一个优雅且安全的移动应用登录及API接口授权系统。


无论身在何处

有我不再孤单孤单

长按识别二维码关注我们




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