Использование собственного Rocket Responder для ошибки в RequestGuard - PullRequest
0 голосов
/ 20 сентября 2019

В приложении веб-сервера, использующем rocket.rs, я использую тип ошибки, который реализует Responder во всем моем API.Этот тип ошибки гарантирует, что все ошибки отображаются одинаково (как RFC 7807 json).

Однако я не могу найти способ использовать эти ответы об ошибках в RequestGuards.Кажется, что функция from_request приводит к Outcome, который использует совершенно другую модель, возвращая Outcome::Failure((Status, T)) при ошибках.

Как я могу гарантировать, что ошибки в этих средствах защиты запросов отображаются в одном и том же JSONформат?Это даже настраиваемо?

Я пытался использовать ловушку, но, похоже, это не позволяет получить какую-либо информацию об ошибке.

1 Ответ

2 голосов
/ 22 сентября 2019

документы для FromRequest * Outcome состояния:

Обратите внимание, что пользователи могут запрашивать типы Result<S, E> и Option<S> для перехвата Failures и получить значение ошибки.

  1. В начале реализации FromRequest определите type Error = JsonValue;

  2. Вfrom_request, убедитесь, что она возвращает request::Outcome<S, Self::Error>, где S - это то, что вы реализуете.

  3. В функции from_request, когда вы хотите вернуть ошибкусделайте что-то вроде Outcome::Failure((Status::Unauthorized, json!({"error": "unauthorised"}))) или что вы хотите вернуть.

  4. В функции вашего маршрута используйте Result<S, JsonValue> в качестве типа защиты запроса, где S - это то, чтовы где внедряете.В вашем маршруте используйте match, чтобы сопоставить его, например, с Ok(S) или Err(json_error).

Возможно, есть способ передать статус Outcome::Failure, ноРешение, которое я описал, означает, что если вы используете настраиваемый респондент, вы устанавливаете статус в респонденте, не основываясь на Outcome::Failure - например, код ниже.

Вот пример, примененный к ApiKey запросить пример защиты у документов, с примером настраиваемого респондента с именем ApiResponse, который устанавливает свой собственный статус:

#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
#[macro_use]
extern crate serde_derive;

use rocket::Outcome;
use rocket::http::{ContentType, Status};
use rocket::request::{self, Request, FromRequest};
use rocket::response::{self, Responder, Response};
use rocket_contrib::json::{Json, JsonValue};

#[derive(Debug)]
pub struct ApiResponse {
    pub json: JsonValue,
    pub status: Status,
}

impl<'r> Responder<'r> for ApiResponse {
    fn respond_to(self, req: &Request) -> response::Result<'r> {
        Response::build_from(self.json.respond_to(req).unwrap())
            .status(self.status)
            .header(ContentType::JSON)
            .ok()
    }
}

#[derive(Debug, Deserialize, Serialize)]
struct ApiKey(String);

/// Returns true if `key` is a valid API key string.
fn is_valid(key: &str) -> bool {
    key == "valid_api_key"
}

impl<'a, 'r> FromRequest<'a, 'r> for ApiKey {
    type Error = JsonValue;

    fn from_request(request: &'a Request<'r>) -> request::Outcome<Self, Self::Error> {
        let keys: Vec<_> = request.headers().get("x-api-key").collect();
        match keys.len() {
            0 => Outcome::Failure((Status::BadRequest, json!({ "error": "api key missing" }))),
            1 if is_valid(keys[0]) => Outcome::Success(ApiKey(keys[0].to_string())),
            1 => Outcome::Failure((Status::BadRequest, json!({ "error": "api key invalid" }))),
            _ => Outcome::Failure((Status::BadRequest, json!({ "error": "bad api key count" }))),
        }
    }
}

#[get("/sensitive")]
fn sensitive(key: Result<ApiKey, JsonValue>) -> ApiResponse {
    match key {
        Ok(_ApiKey) => ApiResponse {
            json: json!({ "data": "sensitive data." }),
            status: Status::Ok
        },
        Err(json_error) => ApiResponse {
            json: json_error,
            status: Status::BadRequest
        }
    }
}

Я новичок в Rust и Rocket, так что это может быть не лучшим решением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...