документы для FromRequest
* Outcome
состояния:
Обратите внимание, что пользователи могут запрашивать типы Result<S, E>
и Option<S>
для перехвата Failure
s и получить значение ошибки.
В начале реализации FromRequest
определите type Error = JsonValue;
Вfrom_request
, убедитесь, что она возвращает request::Outcome<S, Self::Error>
, где S
- это то, что вы реализуете.
В функции from_request
, когда вы хотите вернуть ошибкусделайте что-то вроде Outcome::Failure((Status::Unauthorized, json!({"error": "unauthorised"})))
или что вы хотите вернуть.
В функции вашего маршрута используйте 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, так что это может быть не лучшим решением.