#web-services #alexa #skill #verify #async-client

alexa-verifier

使用 Rust 验证 Alexa 发送的针对自定义 Web 服务技能的请求

3 个不稳定版本

0.2.1 2019年11月14日
0.2.0 2019年11月14日
0.1.2 2019年8月6日
0.1.1 2019年8月6日
0.1.0 2019年8月6日

#2 in #web-service

MIT 许可证

34KB
508

Alexa Rust Web 服务验证器

Crates.io

验证传入请求是否来自 Alexa 的自定义 Web 服务技能。

特性

默认提供同步和异步客户端。它们分别位于功能标志 syncasync 后面。

  • sync 提供 RequestVerifier 客户端
  • async 提供 RequestVerifierAsync 客户端

使用

使用 Rouille 服务器和 alexa_sdk 进行请求反序列化的示例

use crate::skill::process_request; // Entry point to custom skill
use alexa_verifier::RequestVerifier; // Struct provided by this crate
use log::{debug, error, info};
use rouille::{router, Request, Response};
use std::io::Read;

fn note_routes(request: &Request, verifier: &RequestVerifier) -> Response {
    router!(request,
        (POST) (/) => {
            info!("Request received...");

            // Get request body data
            let mut body = request.data().unwrap();
            let mut body_bytes: Vec<u8> = vec![];
            body.read_to_end(&mut body_bytes).unwrap();

            // Get needed headers, default to blank (will cause verification to fail)
            let signature_cert_chain_url = request.header("SignatureCertChainUrl").unwrap_or("");
            let signature = request.header("Signature").unwrap_or("");

            // Deserialize using alexa_sdk::Request
            let _request = serde_json::from_slice::<alexa_sdk::Request>(&body_bytes);
            if let Err(e) = _request {
                error!("Could not deserialize request");
                error!("{:?}", e);
                let response = Response::empty_400();
                info!("Sending back response...");
                debug!("{:?}", response);
                return response;
            }
            let request = _request.unwrap();
            debug!("{:?}", request);

            // alexa-verifier used here, return 400 if verification fails
            if verifier
                .verify(
                    signature_cert_chain_url,
                    signature,
                    &body_bytes,
                    request.body.timestamp.as_str(),
                    None
                ).is_err() {
                    error!("Could not validate request came from Alexa");
                    let response = Response::empty_400();
                    info!("Sending back response...");
                    debug!("{:?}", response);
                    return response;
                };
            debug!("Request is validated...");

            // Entry point custom to skill, returning alexa_sdk::Response
            let response = Response::json(&process_request(request));
            info!("Sending back response...");
            debug!("{:?}", response);
            response
    },
        _ => Response::empty_404()
    )
}

pub fn run() -> std::io::Result<()> {
    info!("Starting server on 0.0.0.0:8086");
    let verifier = RequestVerifier::new();

    rouille::start_server("0.0.0.0:8086", move |request| {
        note_routes(&request, &verifier)
    });
}

许可证:MIT

依赖

~11–15MB
~400K SLoC