actix-web url dispatch and middleware
This commit is contained in:
parent
2dca209684
commit
44d6a24fc8
5
.vscode/settings.json
vendored
Normal file
5
.vscode/settings.json
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"cSpell.words": [
|
||||
"Actix"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
title: "actix-web Url Dispatch and Middleware"
|
||||
date: 2022-04-24T03:37:47-04:00
|
||||
draft: false
|
||||
toc: false
|
||||
images:
|
||||
tags:
|
||||
- dev
|
||||
- rust
|
||||
---
|
||||
|
||||
I've hit an issue with `actix-web` recently, and ended up learning a bit about
|
||||
how it does routing (or URL dispatch as they name it).
|
||||
|
||||
Here's a simplified version of my problem:
|
||||
|
||||
```rust
|
||||
// service code
|
||||
#[get("/{path:.*}")]
|
||||
pub async fn basic_handler(params: web::Path<String>) -> HttpResponse {
|
||||
// ...
|
||||
}
|
||||
|
||||
#[post("/auth/")]
|
||||
pub async fn auth_handler() -> HttpResponse {
|
||||
// ...
|
||||
}
|
||||
|
||||
// in main
|
||||
let auth_service = web::scope("")
|
||||
.wrap(auth_middleware)
|
||||
.service(auth_handler);
|
||||
App::new()
|
||||
.service(authenticated_scope)
|
||||
.service(basic_handler)
|
||||
```
|
||||
|
||||
`auth_middleware` is a custom middleware I wrote which checks for the existence
|
||||
of an auth token in a header or cookie, then validates the token. The middleware
|
||||
responds early with a 401 if the token is missing, which ensures that the
|
||||
protected handlers can only be reached by authenticated users.
|
||||
|
||||
I expected Actix to realize that if a request doesn't match `/auth/`, it should
|
||||
go to the `basic_handler` and the authentication middleware shouldn't run. But
|
||||
the middleware did run even if the path had nothing to do with `/auth/`! That
|
||||
would cause the middleware to respond with a 401 and stops it from propagating,
|
||||
so it never reached `basic_handler`.
|
||||
|
||||
The solution, it turns out, is using the `web::scope` to scope out the
|
||||
authenticated routes. If the scope doesn't match, Actix then seems to skip over
|
||||
that entire scope and never runs the middleware. Here's the same code, fixed:
|
||||
|
||||
```rust
|
||||
// service code
|
||||
#[get("/{path:.*}")]
|
||||
pub async fn basic_handler(params: web::Path<String>) -> HttpResponse {
|
||||
// ...
|
||||
}
|
||||
|
||||
#[post("/")] // <-- change here
|
||||
pub async fn auth_handler() -> HttpResponse {
|
||||
// ...
|
||||
}
|
||||
|
||||
// in main
|
||||
let auth_service = web::scope("/auth") // <-- change here
|
||||
.wrap(auth_middleware)
|
||||
.service(auth_handler);
|
||||
App::new()
|
||||
.service(authenticated_scope)
|
||||
.service(basic_handler)
|
||||
```
|
Loading…
Reference in a new issue