Поделитесь информацией о сеансе с железным обработчиком

Я пытаюсь реализовать веб-API, используя Iron в качестве практического упражнения. Мой сеанс представляет собой следующую структуру, которая будет закодирована как JWT. Каждый раз, когда я получаю запросы от клиентов, некоторым обработчикам потребуется доступ к user_id;

#[derive(Serialize, Deserialize)]
struct Session {
    session_id: i32,
    user_id: Option<i32>,
    expiration: u64,
}

Есть несколько способов сделать это, но я не знаю самого идиоматичного и наименее подробного. Я думал что-то вроде:

fn handle(&self, req: &mut Request) -> IronResult<Response> {
    let session = match get_session(req) {
        Err(err) => return Ok(Response::with((status::BadRequest, err.description()))),
        Ok(session) => session,
    };
    Ok(Response::with((status::Ok, err.description())))
}

Но таким образом мне понадобится этот фрагмент на нескольких конечных точках.

Я мог бы использовать промежуточное программное обеспечение, но я не знаю, как перехватить значение структуры между промежуточным программным обеспечением.


person Danilo    schedule 08.11.2017    source источник
comment
В настоящее время я так делаю: github.com/dnp1/api/ blob/master/src/file.rs (метод FileDelete::handler) github.com/dnp1/api/blob/master/src/util.rs (полезный код) Но это выглядит слишком шаблонно, я не думаю, что это идиоматично   -  person Danilo    schedule 08.11.2017
comment
Я создал проблему в своем репо. Так что я запомню это. github.com/dnp1/api/issues/1 В настоящее время я нашел подробное решение. Спасибо @Shepmaster за исправления грамматики, я плохо говорю по-английски   -  person Danilo    schedule 08.11.2017
comment
Я пробовал это gist.github.com/dnp1/ffcb6a93e05dca76b87ac5b7e9dd994e, но отчет компилятора: трейт for<'r, 'r, 'r> std::ops::Fn<(&'r mut iron::Request<'r, 'r>,)> не реализован для file::FileDelete   -  person Danilo    schedule 09.11.2017


Ответы (1)


В итоге я использовал обертку:

pub trait SessionHandler {
    fn session_manager(&self) -> &SessionManager;
    fn authenticated(&self) -> bool {
        false
    }
    fn handle_session(&self, session: &mut Session, req: &mut Request) -> IronResult<Response>;

    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        let mut session = match self.session_manager().get_request_session(req) {
            None => return Ok(Response::with((status::Unauthorized, ""))),
            Some(session) => {
                if self.authenticated() {
                    if let None = session.user_id {
                        return Ok(Response::with((status::Forbidden, "")));
                    }
                }
                session
            }
        };
        self.handle_session(&mut session, req)
    }
}

pub struct SessionHandlerBox<T> {
    pub s: T
}

impl <T> Handler for SessionHandlerBox<T> where T: SessionHandler +  Send + Sync + 'static {
    fn handle(&self, r: &mut Request) -> IronResult<Response> {
        self.s.handle(r)
    }
}

Поэтому я использую:

struct FileDelete {
    db: Arc<Pool<PostgresConnectionManager>>,
    sm: Arc<SessionManager>,
}

impl SessionHandler for FileDelete {
    fn session_manager(&self) -> &SessionManager {
        self.sm.as_ref()
    }
    fn handle_session(&self, session: &mut Session, req: &mut Request) -> IronResult<Response> {
        Ok(Response::with((status::Ok, "")))
    }
}

Есть еще шаблон, но меньше «бизнес-логики». Любые лучшие решения приветствуются.

пример использования:

 pub fn register_handlers<'s>(db: Pool<PostgresConnectionManager>, r: &'s mut Router, sm : Arc<SessionManager>) {
    let file_delete = FileDelete { db: Arc::new(db), sm: sm.clone() };
    r.delete("/file", SessionHandlerBox {s: file_delete}, "file_delete");
}
person Danilo    schedule 08.11.2017
comment
Текущую версию можно найти в репозитории github.com/dnp1/api/blob. /master/src/util.rs - person Danilo; 10.11.2017