actix / actix-extras

A collection of additional crates supporting the actix and actix-web frameworks.
https://actix.rs
Apache License 2.0
775 stars 199 forks source link

How to implement multiple auth methods #295

Open mike-lloyd03 opened 2 years ago

mike-lloyd03 commented 2 years ago

I tried to ask this question on the Gitter channel linked in the new issue form but it appears to be dead.

I am trying to implement two optional forms of authentication on my REST API: cookie (using actix-session) and bearer token (using actix-web-httpauth). My thought would be to check if the Authorization: Bearer <token> header is present first, if it isn't, then allow the request to be handled by the session middleware. However, I see no way to handle the case where the bearer header is missing without returning a 401. I see the idea of an optional auth header has been raised a few times (#156 , #137 , #6 ) and it was suggested that there are existing methods to handle this and such a feature won't be implemented. However, I wasn't able to find any way to achieve this.

I see an "optional auth extractor" was merged in #205 but I'm not clear on how to use this as there's nothing in the documentation referring to it.

Can someone please describe a way to implement multiple authentication methods?

TurtIeSocks commented 1 year ago

+1

TurtIeSocks commented 1 year ago

It looks like #205 was removed in #264. Been poking around most of the morning on how to impl WithRequest as the PR mentions but can't seem to get it. Would greatly appreciate any insight on how to do this.

mohsenpakzad commented 1 year ago

As I discovered, if you want to use optional auth extractor, just make BearerAuth be an option in your validator and use HttpAuthentication::with_fn function instead of HttpAuthentication::bearer.

use actix_web::{App, HttpServer}; // version 4.2.1
use actix_web_httpauth::middleware::HttpAuthentication; // version 0.8.0

pub async fn validator(
    req: ServiceRequest,
    credentials: Option<BearerAuth>,
) -> Result<ServiceRequest, (Error, ServiceRequest)> {
      ...
}

HttpServer::new(move || { 
        App::new()
            .wrap(HttpAuthentication::with_fn(validator))
            ...
})
TurtIeSocks commented 1 year ago

Just tried this and works beautifully. Thank you @mohsenpakzad! I think it would be a good idea to add this as official example code.