rust api接口开发(以登陆和中间件鉴权为例)

rust rest api接口开发

所需依赖

  • axum
  • tokio
  • redis
cargo add axum redis
cargo add tokio --features=full

路由服务创建和运行

//子路由
let v1router = axum::Router::new();
//主路由,并将子路由绑定到主路由
let router=axum::Router::new().nest("/v1",v1router);let l = tokio::net::TcpListener::bind("0.0.0.0:8080").await.expect("bind 8080 failed");axum::serve(l, router).await.expect("serve server failed");

handle 函数到路由

router调用route等函数后会转移自身,所以你可以选择两种方式使用router:链式调用,和重新赋值
链式调用

use axum::routing::get;
let router=axum::Router::new().route("/echo1",get(echo1)).route("/echo2",post(echo2));

重新赋值

use axum::routing::get;
let router=axum::Router::new();
let router=router.route("/echo1",get(echo1));
let router=router.route("/echo2",get(echo2));

handler 函数
rust axum的handler函数相对于golang 的web框架来讲要比较智能,他已经帮你自动做好mvc中的controller层,而golang的gin框架和iris都需要或多或少自己实现或者使用mvc脚手架(例如iris/mvc),更要命的是大部分脚手架都是使用golang运行时反射实现的,性能相对于在编译期间通过宏来静态反射生成的要差许多
这是一个简单的不需要任何参数,直接返回hello的接口。当然如果你需要从body中读取json或者原body都可以在函数参数加,axum会自动识别,响应如果需要制定status也可以在响应里添加StatusCode

let router=router.route("/greet",get(||async{Html("hello")
}));

这个接口也可以这样写

let router=router.route("/greet",get(greets));//函数定义
async fn greets()->Html<&'static str>{return Html("hello");}

中间件

let router=router.layer(axum::middleware::from_fn(|req:Request,next:axum::middleware::Next|async{
//做你想做的操作,next.run等效于golang web框架中xxx.Context 下的Next()next.run(req).await
}));

Service注册

let router = router.layer(axum::Extension(Arc::new(WebService::new(AuthService::new("redis://localhost:6379"),
))));

以登陆和鉴权接口演示

这里以登陆和鉴权接口进行演示,登陆成功后将token存入redis中. 为了方便演示流程,就直接忽略数据库里查询匹配,用户名和密码一样就模拟通过

#[cfg(test)]
mod web{use std::sync::Arc;use axum::{extract::Request, http::HeaderMap, middleware::Next, response::Html, Extension, Json,};use tokio::sync::Mutex;#[tokio::test]async fn start() {let v1router = axum::Router::new().route("/greet", axum::routing::get(greet)).layer(axum::middleware::from_fn(|Extension(ext): Extension<Arc<WebService>>,mut req: Request, next: Next| async move {//token校验,没有什么也不返回,当前中间件只对v1router中服务生效let token = req.headers().get("token");if let None = token {return axum::http::Response::<axum::body::Body>::new(axum::body::Body::empty(),);}let token = token.unwrap().to_str().unwrap();let mut bl = ext.auth_service.lock().await;let username=bl.check_token(token.to_string());if let None=username{eprintln!("not found token {token}");return axum::http::Response::<axum::body::Body>::new(axum::body::Body::empty(),);}let username=username.unwrap();req.headers_mut().insert("userName", username.as_str().parse().unwrap());drop(bl);let response: axum::http::Response<axum::body::Body> = next.run(req).await;response},));let router = axum::Router::new().route("/login", axum::routing::post(login)).nest("/v1", v1router).layer(axum::Extension(Arc::new(WebService::new(AuthService::new("redis://localhost:6379"),))));let l = tokio::net::TcpListener::bind("0.0.0.0:8080").await.expect("bind 8080 failed");axum::serve(l, router).await.expect("serve server failed");}async fn login(Extension(ext): Extension<Arc<WebService>>,Json(req): Json<args::Login>,) -> Json<resp::Response<String>> {let mut bll = ext.auth_service.lock().await;match bll.login(req.username, req.password) {None => Json(resp::Response::error("login failed")),Some(token) => Json(resp::Response::ok(token)),}}async fn greet(headers: HeaderMap) -> Json<resp::Response<String>> {let username = headers.get("userName").unwrap().to_str().unwrap();Json(resp::Response::ok(format!("hello {username}")))}struct WebService {auth_service: Mutex<AuthService>,}impl WebService {pub fn new(auth: AuthService) -> Self {Self {auth_service: Mutex::new(auth),}}}struct AuthService {red_conn: redis::Client,}impl AuthService {pub fn new(uri: &str) -> Self {Self {red_conn: redis::Client::open(uri).expect("connect to redis failed"),}}pub fn login(&mut self, username: String, password: String) -> Option<String> {if username != password {return None;}let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_millis();let now = (now % (1 << 32)) as u32;let token = format!("{:2x}", now);let mut conn = self.red_conn.get_connection().expect("get redis connection failed");let ans = redis::cmd("set").arg(token.as_str()).arg(username).arg("EX").arg(60 * 60).exec(&mut conn);if let Err(err) = ans {eprintln!("set token to redis error {err}");}Some(token)}pub fn check_token(&mut self, token: String) -> Option<String> {let mut conn = self.red_conn.get_connection().expect("get redis connection failed");let ans = redis::cmd("get").arg(token.as_str()).query::<String>(&mut conn);match ans {Ok(data) => Some(data),Err(err) => {eprintln!("check from redis failed {err}");None}}}}mod args {#[derive(serde::Deserialize)]pub struct Login {pub username: String,pub password: String,}}mod resp {#[derive(serde::Serialize)]pub struct Response<T> {ok: bool,reason: &'static str,data: Option<T>,}impl<T> Response<T> {pub fn ok(data: T) -> Self {Self {ok: true,reason: "",data: Some(data),}}pub fn error(reason: &'static str) -> Self {Self {ok: false,reason: reason,data: None,}}}}}

结果展示

测试脚本

#!/bin/bash
function login(){curl -H 'Content-Type:application/json' -X POST http://localhost:8080/login -d '{"username":"jesko","password":"jesko"}'
}
function greet(){curl -H "token:$token" -X GET http://localhost:8080/v1/greet
}
for va in "$@";do$va
done

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/408612.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pytorch实现CIFAR10训练模型

文章目录 简述模型结构模型参数、优化器、损失函数参数初始化优化器损失函数 模型训练、测试集预测、模型保存、日志记录训练测试集测试模型保存模型训练完整代码 tensorboard训练可视化结果train_loss测试准确率测试集loss 模型应用模型独立应用代码api.py预测结果 简述 使用…

Axure设计之三级菜单导航教程(中继器)

中继器作为复杂的元件&#xff0c;通常被用来制作“高保真”的动态原型&#xff0c;以达到良好的视觉效果和交互效果。本文将教大家通过AxureRP9工具如何使用中继器设计三级菜单导航。 一、案例效果 原型预览&#xff1a;https://1zvcwx.axshare.com 主要效果&#xff1a; 1…

数据结构(Java实现):链表与LinkedList

文章目录 1. 单向链表1.1 链表的概念及结构1.2 链表的实现1.2.1 单向链表类和节点1.2.2 打印每个节点的值1.2.3 计算链表长度1.2.4 头插节点1.2.5 尾插节点1.2.6 在指定下标插入新节点1.2.7 判断是否存在某个节点1.2.8 移除某个节点1.2.9 移除所有指定节点1.2.10 清空链表1.2.1…

redis | 认识非关系型数据库Redis的哈希数据类型

Redis 非关 kv型 哈希通用命令python 操作hash应用场景 数据类型 数据类型丰富&#xff0c;字符串strings,散列hashes,列表lists&#xff0c;集合sets,有序集合sorted sets等等 哈希 定义 1、由field和关联的value组成的键值对 类似于python的键值对 2、field和value.是字符…

一文学会Shell中case语句和函数

大家好呀&#xff01;今天简单聊一聊Shell中的case语句与函数。在多选择情况下使用case语句将非常方便&#xff0c;同时&#xff0c;函数的学习和使用对于学好一门编程语言也是非常重要的。 一、case语句 case语句为多选择语句。可以用case语句匹配一个值与一个模式&#xff0c…

OpenCV绘图函数详解及其用法示例

MFC类库中的CDC类有划线,画矩形,画椭圆,画多边形,文字等绘图函数,OpenCV也有类似的绘图函数。二者的区别在于MFC画图是在一定的区域内绘制图形,而OpenCV则是在图像上绘制,主要用于图像标注。 OpenCV的常用绘图函数有arrowedLine,circle ,drawContours, drawMarker, dra…

AI数字时代客户体验白皮书5G云算力网络云网终端AIGC人工智能宽带政企物联网专线 IDC智慧城市专家学者教授培训讲师分享

客户体验的时代已然来临 在过去的几十年里&#xff0c;中国企业逐步从产品驱动转向市场驱动&#xff0c;从规模竞争走向创新竞争。然而&#xff0c;随着市场竞争的白热化和产品、服务的高度同质化&#xff0c;企业之间的差异化逐渐被削弱&#xff0c;传统的价格战、渠道战已经…

layui table表单 checkbox选中一个其它也要选中

当我们选中其中一个商品的时候同类型的商品状态也要跟着改变 所以要在表单加载完成后去监听checkbox ,done:function (res) {console.log(详情表格数据,res)tableDetailList res.data;// 监听表格复选框选择table.on(checkbox( INST_SELECTORS.instLayFilters.unpaidTableDe…

Python优化算法13——飞蛾扑火优化算法(MFO)

科研里面优化算法都用的多&#xff0c;尤其是各种动物园里面的智能仿生优化算法&#xff0c;但是目前都是MATLAB的代码多&#xff0c;python几乎没有什么包&#xff0c;这次把优化算法系列的代码都从底层手写开始。 需要看以前的优化算法文章可以参考&#xff1a;Python优化算…

用4种不同视角理解矩阵乘法

目录 1. 背景 2. 线性方程组视角&#xff08;向量点积视角&#xff09; 3. 列向量观点视角 4. 向量变换视角&#xff08;矩阵函数&#xff09; 5. 坐标变换视角 1. 背景 矩阵诞生于线性方程组的求解&#xff0c;最基本的运算方法来自于高斯消元法&#xff0c;所以矩阵整个…

Linux 离线安装docker和docker-compose

前言 公司有 docker 和 docker-compose 离线包安装部署的需求&#xff0c;本文应运而生撰写时间&#xff1a;2024-06-07&#xff08;初稿&#xff09; 1 应用版本 docker&#xff1a;20.10.7, build f0df350docker-compose&#xff1a;1.25.1 2 物料准备 服务器账号/密码d…

[数据集][目标检测]电力场景输电线防震锤检测数据集VOC+YOLO格式2721张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2721 标注数量(xml文件个数)&#xff1a;2721 标注数量(txt文件个数)&#xff1a;2721 标注…

《javaEE篇》--线程池

线程池是什么 线程的诞生是因为进程创建和销毁的成本太大&#xff0c;但是也是相对而言&#xff0c;如果频繁的创建和销毁线程那么这个成本就不能忽略了。 一般有两种方法来进一步提高效率&#xff0c;一种是协程(这里不多做讨论),另一种就是线程池 假如说有一个学校食堂窗口…

智能控制,高效节能。ZLG致远电子能源智慧管理解决方案

面对楼宇及建筑群能源管理与设备控制的复杂需求&#xff0c;ZLG致远电子推出了一套能源智慧管理解决方案。该方案集设备管理、任务调度和数据可视化于一体&#xff0c;不仅实现数据的实时监控与分析&#xff0c;还助力系统节能降耗。 ZLG致远电子能源智慧管理解决方案 在ZLG致…

ShareSDK 企业微信

本篇文档主要讲解如何使用企业微信并进行分享和授权。 创建应用 登录企业微信并通过企业认证。选择应用管理 > 应用 >创建应用。编辑应用信息。配置授权登录信息。 以下为创建过程示例&#xff0c;图中信息仅为示例&#xff0c;创建时请按照真实信息填写&#xff0c;否…

如何查看ubuntu版本

在当前的技术环境中&#xff0c;了解操作系统的具体版本对于用户来说至关重要。这不仅能确保软件兼容性&#xff0c;还有助于进行系统管理和故障排查。对于使用Ubuntu系统的用户来说&#xff0c;有几种不同的方法可以查看当前系统的版本。下面将详细介绍如何查看您的Ubuntu系统…

Spring Boot(快速上手)

Spring Boot 零、环境配置 1. 创建项目 2. 热部署 添加依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional> </dependency&…

polarctf靶场[WEB]cookie欺骗、upload、签到

[web]cookie欺骗 考点&#xff1a;cookie值 工具&#xff1a;Burp Suite抓包 根据题目提示&#xff0c;cookie欺骗&#xff0c;所以要在cookie值寻找关键 进入网页之后&#xff0c;说只有admin用户才能得到flag&#xff0c;而我们此时只属于普通访客 我们查看cookie值&…

「Python程序设计」基本数据类型:字符串

​在python的程序设计过程中&#xff0c;字符串是需要经常处理的变量类型。字符串在程序中的存储方式&#xff0c;类似于一维数组&#xff0c;每个字符占据数组中的一个单元格。 字符串可以存储字符类型的变量&#xff0c;即使是数字类型&#xff0c;也可以通过字符串来进行存…

vue3+vite配置环境变量实现开发、测试、生产的区分

文章目录 一、为什么需要区分 (dev)、测试 (test) 和生产 (prod) 环境二、vue3的项目如何通过配置方式区分不同的环境1、创建不同环境的.env文件2、在不同的.env文件中配置相应的环境变量1&#xff09;.env.develoment2&#xff09;.env.test3&#xff09;.env.production 3、在…