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

news2024/11/13 15:08:54

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.coloradmin.cn/o/2057966.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Zabbix6.4监控Windows上的GPU使用率

背景&#xff1a;一台Windows物理机上装了英伟达的GPU显卡&#xff0c;业务需要实时监控它的使用率。 1、确认nvidia-smi命令可用 2、命令查询相关使用情况 3、服务器上部署zabbix-agent 提前下载好包上传&#xff0c;路径自行修改 C:\Users\Administrator>C:\zabbix_age…

集团数字化转型方案(三)

集团数字化转型方案通过系统整合人工智能&#xff08;AI&#xff09;、大数据、云计算和物联网&#xff08;IoT&#xff09;技术&#xff0c;建立了一个全面智能化的业务管理平台&#xff0c;涵盖从业务流程自动化、数据驱动决策支持&#xff0c;到客户体验优化和供应链管理的各…

Redis基础到高级狂神笔记一篇总结完

学习视频&#xff1a;【狂神说Java】Redis最新超详细版教程通俗易懂_哔哩哔哩_bilibili 目录 1.为什么用NoSQL 1.1单机MySQL的美好年代 1.2 Memcached&#xff08;缓存&#xff09; MySQL 垂直拆分(读写分离) 1.3分表分库 水平拆分 Mysql 集群 1.4现今 1.5为什么用NoSQL&…

『深度长文』4种有效提高LLM输出质量的方法!

大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,专注于分享AI全维度知识,包括但不限于AI科普,AI工具测评,AI效率提升,AI行业洞察。关注我,AI之路不迷路,2024我们一起变强。 LLM,全…

C#发送邮件功能实现全面指南?有哪些方法?

C#发送邮件性能优化技巧&#xff1f;C#发信时如何设置邮件格式&#xff1f; 在现代应用程序开发中&#xff0c;发送电子邮件是一个常见的需求。无论是发送通知、警报&#xff0c;还是定期报告&#xff0c;邮件功能都是至关重要的。AokSend将详细探讨如何在C#中实现发送邮件的功…

为什么要使用TikTok云手机

随着TikTok平台的日益繁荣&#xff0c;TikTok云手机作为一种新兴的运营工具&#xff0c;正以其独特的云端技术和用户体验&#xff0c;赢得广大用户的青睐。相较于传统手机&#xff0c;TikTok云手机通过云端技术为用户带来了一系列新的优势&#xff0c;让TikTok运营变得更加灵活…

读软件开发安全之道:概念、设计与实施04缓解

1. 缓解 1.1. 安全思维转换为有效行动的方法就是首先预判威胁&#xff0c;然后针对可能的漏洞加以保护 1.2. 主动响应的做法就叫做“缓解” 1.2.1. mitigation 1.2.2. 喂宝宝的时候给孩子围上围嘴&#xff0c;避免掉下来的食物粘在宝宝的衣服上&#xff0c;还有安全带、限速…

虚幻引擎游戏开发 | 程序化生成道具位置 Randomize Height

当地图上有无数个收集物【如水晶】&#xff0c;一键随机化高度 应用前 应用后 这时候水晶的高度是离散型地在0和110两个数中平均概率地选择。 如果要有权重地分布高度&#xff0c;减少高位水晶的比例&#xff08;由于过多连续跳跃会让玩家无聊和难以持续专注&#xff09;可以加…

leetcode_62. 不同路径 + 63. 不同路径 II

62. 不同路径 题目描述&#xff1a;一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为 “Finish” &#xff09;。问总共有多少条…

第1章-01-为什么主要选择用Python来做爬虫

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌&#xff0c;CSDN博客专家&#xff0c;阿里云社区专家博主&#xff0c;2023年CSDN全站百大博主。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&am…

Nacos配置中心组件学习

Nacos配置中心组件学习 1. Nacos简介1.1 Nacos是啥1.2 作用 2. springCloud项目集成2.1 maven依赖2.2 Nacos配置相关参数2.3 配置信息2.5 配置使用2.6 获取实时配置 3. nacos自动装配3.1 配置加载原理3.2 配置实时刷新原理 4. nacos配置中心原理3.1. 动态配置管理3.2. 配置存储…

这家AGV机器人龙头高歌猛进,半年营收27亿,国内对手们慌了吗?

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 机器人业务高歌猛进&#xff0c;海康威视创新引擎全速运转 海康威视于近日揭晓了其2024年上半年的辉煌成绩单。这份报告不仅彰显了公司整体业务的稳健增长&#xff0c;更引人注目的是…

Mybatis 一文速通 节约学习或复习成本

目录 1、简介 1.1、什么是Mybatis 1.2、持久化 1.3持久层 1.4为什么需要Mybatis&#xff1f; 2、第一个Mybatis程序 2.1、搭建环境 2.2、创建一个模块 2.3、编写代码 2.4、测试 3、CRUD 1、namespace 2、select 3、insert 4、update 5、delete 6、常见错误分析…

Linux进程间通信学习记录(IPC 机制、共享内存以及信号灯集)

0.System V IPC机制&#xff1a; ①.IPC对象包含&#xff1a;共享内存、消息队列和信号灯集。 ②.每个IPC对象有唯一的ID。 ③.IPC对象创建后一直存在&#xff0c;直到被显示地删除。 ④.每一个IPC对象有一个关联的KEY。&#xff08;其他进程通过KEY访问对应的IPC对象&#xff…

SpringCloud远程调用为啥要采用HTTP,而不是RPC?

关于SpringCloud远程调用采用HTTP而非RPC。 1. 首先SpringCloud开启Web服务依赖于内部封装的Tomcat容器&#xff0c;而今信息飞速发展&#xff0c;适应大流量的微服务&#xff0c;采用Tomcat处理HTTP请求&#xff0c;开发者编写Json作为资源传输&#xff0c;服务器做出相应的响…

Flutter【01】状态管理

声明式编程 Flutter 应用是 声明式 的&#xff0c;这也就意味着 Flutter 构建的用户界面就是应用的当前状态。 当你的 Flutter 应用的状态发生改变时&#xff08;例如&#xff0c;用户在设置界面中点击了一个开关选项&#xff09;你改变了状态&#xff0c;这将会触发用户界面…

flume--数据从kafka到hdfs发生错误

解决&#xff1a; #1.将flume自带的依赖删除 mv /opt/installs/flume1.9/lib/guava-11.0.2.jar /opt/installs/flume1.9/lib/guava-11.0.2.jar.bak #2.将hadoop的依赖发送到flume下 cp /opt/installs/hadoop3.1.4/share/hadoop/common/lib/guava-27.0-jre.jar /opt/installs/f…

招商期货:以超融合支撑期货重要业务,承载80%信创系统

招商期货有限公司&#xff08;以下简称“招商期货”&#xff09;成立于 1993 年&#xff0c;是招商证券股份有限公司的全资子公司&#xff0c;注册资本 35.98 亿元&#xff0c;是中国首批券商全资控股期货公司。 随着数字化进程快速推进、交易模式不断创新&#xff0c;系统建设…

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

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

异步交互技术Ajax-Axios

目录 一、同步交互和异步交互 二、Ajax 1.概述 2.如何实现ajax请求 三、异步传输数据乱码的问题 regist.html页面代码 服务端代码处理 四、Axios 1. Axios的基本使用 &#xff08;1&#xff09;引入Axios文件 &#xff08;2&#xff09;使用Axios发送请求&#xff0…