2 changed files with 77 additions and 0 deletions
@ -0,0 +1,5 @@
@@ -0,0 +1,5 @@
|
||||
{ |
||||
"cSpell.words": [ |
||||
"Actix" |
||||
] |
||||
} |
@ -0,0 +1,72 @@
@@ -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 new issue