Repository: rmqtt/rmqtt (language: rust)

Issue:
[Feature Requset] http api plugin support auth method
It's very useful when build simple demo without building proxy http server for MQTT http api plugin.

当构建简单原型时， 若http api plugin 补上鉴权（可以很简单，例如添加个 HTTP Header: `Authorization: $token`），就不需要另外构建个 http 服务来做此类事情了。


Discussion / hints:
非常好的建议，之后的版本会考虑这个特性。



---- 回复的原邮件 ----
| 发件人 | ***@***.***> |
| 日期 | 2024年05月24日 18:01 |
| 收件人 | ***@***.***> |
| 抄送至 | ***@***.***> |
| 主题 | [rmqtt/rmqtt] [Feature Requset] http api plugin support auth method (Issue #60) |

It's very useful when build simple demo without building proxy http server for MQTT http api plugin.

当构建简单原型时， 若http api plugin 补上鉴权（可以很简单，例如添加个 HTTP Header: Authorization: $token），就不需要另外构建个 http 服务来做此类事情了。

—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>

Fix patch:
diff --git a/docs/en_US/http-api.md b/docs/en_US/http-api.md
index 8b47c951..dd419761 100644
--- a/docs/en_US/http-api.md
+++ b/docs/en_US/http-api.md
@@ -37,6 +37,8 @@ max_row_limit = 10_000
 http_laddr = "0.0.0.0:6060"
 ## Indicates whether to print HTTP request logs
 http_request_log = false
+## If set, will check request header Authorization value == Bearer $http_bearer_token, default value is undefined
+#http_bearer_token = bearer_token
 
 ##Whether support retain message, true/false, default value: true
 message_retain_available = true
diff --git a/docs/zh_CN/http-api.md b/docs/zh_CN/http-api.md
index 366b0850..d9fefc24 100644
--- a/docs/zh_CN/http-api.md
+++ b/docs/zh_CN/http-api.md
@@ -35,6 +35,8 @@ max_row_limit = 10_000
 http_laddr = "0.0.0.0:6060"
 ## Indicates whether to print HTTP request logs
 http_request_log = false
+## If set, will check request header Authorization value == Bearer $http_bearer_token, default value is undefined
+#http_bearer_token = bearer_token
 
 ##Whether support retain message, true/false, default value: true
 message_retain_available = true
diff --git a/rmqtt-plugins/rmqtt-http-api/src/api.rs b/rmqtt-plugins/rmqtt-http-api/src/api.rs
index f3aae464..0fe22baa 100644
--- a/rmqtt-plugins/rmqtt-http-api/src/api.rs
+++ b/rmqtt-plugins/rmqtt-http-api/src/api.rs
@@ -34,10 +34,37 @@ use super::types::{
 use super::PluginConfigType;
 use super::{clients, plugin, subs};
 
-fn route(cfg: PluginConfigType) -> Router {
-    Router::with_path("api/v1")
+struct BearerValidator {
+    token: String
+}
+impl BearerValidator {
+    pub fn new(token: &str) -> Self {
+        Self {
+            token: format!("Bearer {token}")
+        }
+    }
+}
+
+#[async_trait]
+impl Handler for BearerValidator {
+    async fn handle(&self, req: &mut Request, depot: &mut Depot, res: &mut Response, ctrl: &mut FlowCtrl) {
+        if req.headers().get("authorization").is_some_and(|token|  token == &self.token) {
+            ctrl.call_next(req, depot, res).await;
+        } else {
+            res.status_code(StatusCode::UNAUTHORIZED);
+            ctrl.skip_rest()
+        }
+    }
+}
+
+fn route(cfg: PluginConfigType, token: Option<String>) -> Router {
+    let mut router = Router::with_path("api/v1")
         .hoop(affix::inject(cfg))
-        .hoop(api_logger)
+        .hoop(api_logger);
+    if let Some(token) = token {
+        router = router.hoop(BearerValidator::new(&token));
+    }
+    router
         .get(list_apis)
         .push(Router::with_path("brokers").get(get_brokers).push(Router::with_path("<id>").get(get_brokers)))
         .push(Router::with_path("nodes").get(get_nodes).push(Router::with_path("<id>").get(get_nodes)))
@@ -91,9 +118,9 @@ pub(crate) async fn listen_and_serve(
     cfg: PluginConfigType,
     rx: oneshot::Receiver<()>,
 ) -> Result<()> {
-    let (reuseaddr, reuseport) = {
+    let (reuseaddr, reuseport, http_bearer_token) = {
         let cfg = cfg.read().await;
-        (cfg.http_reuseaddr, cfg.http_reuseport)
+        (cfg.http_reuseaddr, cfg.http_reuseport, cfg.http_bearer_token.clone())
     };
     log::info!("HTTP API Listening on {}, reuseaddr: {}, reuseport: {}", laddr, reuseaddr, reuseport);
 
@@ -108,7 +135,7 @@ pub(crate) async fn listen_and_serve(
         rx.await.ok();
         handler.stop_graceful(None);
     });
-    server.try_serve(route(cfg)).await?;
+    server.try_serve(route(cfg, http_bearer_token)).await?;
     Ok(())
 }
 
diff --git a/rmqtt-plugins/rmqtt-http-api/src/config.rs b/rmqtt-plugins/rmqtt-http-api/src/config.rs
index d1997aef..3047d6a2 100644
--- a/rmqtt-plugins/rmqtt-http-api/src/config.rs
+++ b/rmqtt-plugins/rmqtt-http-api/src/config.rs
@@ -25,6 +25,8 @@ pub struct PluginConfig {
     )]
     pub metrics_sample_interval: Duration,
 
+    pub http_bearer_token: Option<String>,
+
     #[serde(default = "PluginConfig::message_type_default")]
     pub message_type: MessageType,
 


Test patch: