401:仅在使用 fetch 请求数据时出现未授权错误

问题描述 投票:0回答:2

我试图从本地主机上运行的 API 获取响应,我从登录端点获得了生成的不记名令牌,现在我只想使用该令牌来获取用户对其的声明。我的获取请求如下:

const token = "MY_TOKEN";

(async () => {
    let response = await fetch('http://127.0.0.1:8080/auth/restricted/me', {
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${token}`
        }
    });

    console.log(response.status);
})();

这总是会导致 401 未经授权的错误。

但是,如果我尝试使用其他测试客户端(例如邮递员或 insomnia,甚至 VS 代码的雷鸟扩展)执行相同的请求,它会正常工作。我做错了什么?

用于检查 Bearer 令牌的中间件是使用 jwt_simple 包的 Rust Actix Web 中间件。如果有帮助的话,这也是它的代码:

use actix_web::{dev::ServiceRequest, web::Data};
use actix_web_httpauth::extractors::{
    bearer::{self, BearerAuth},
    AuthenticationError,
};
use jwt_simple::prelude::MACLike;

use crate::{models::user::User, AppState};

pub async fn validator(
    req: ServiceRequest,
    credentials: BearerAuth,
) -> Result<ServiceRequest, (actix_web::Error, ServiceRequest)> {
    let key = &req
        .app_data::<Data<AppState<User>>>()
        .clone()
        .unwrap()
        .signing_key;
    match key.verify_token::<User>(credentials.token(), None) {
        Ok(_) => return Ok(req),
        Err(_) => {
            println!("Credential Token {} did not verify!", credentials.token());
            let config = req
                .app_data::<bearer::Config>()
                .cloned()
                .unwrap_or_default()
                .scope("home");

            return Err((AuthenticationError::from(config).into(), req));
        }
    }
}

到目前为止,我已尝试将 fetch 的

mode
属性设置为
"cors"
,但服务器日志除了 401 授权之外没有说明太多内容,这要么意味着获取令牌时出现问题,要么令牌在某些情况下被修改点。

编辑:从标题中删除了内容类型

node.js rust fetch-api bearer-token actix-web
2个回答
0
投票

看来我已经明白为什么会出现问题,在我的网关服务中,我正在重定向我的所有请求,如下所示:

App::new()
            .wrap(Logger::default())
            .wrap(cors)
            .wrap(ratelimit_middleware)
            .service(ping)
            .wrap_fn(|req, srv| {
                log::info!("{:#?}", req.headers());
                srv.call(req)
            })
            .service(
                web::scope("/auth")
                    .service(web::redirect(
                        "/ping",
                        format!(
                            "http://{}:{}/ping",
                            config_clone.auth_service.address, config_clone.auth_service.port
                        ),
                    ))
)

这在大多数 HTTP 客户端上不起作用,因为发生重定向时授权标头会从请求中剥离,默认情况下这是出于安全原因

要解决此问题,我们必须使用

Client
API,我使用
awc
箱将标头复制到新请求中,并通过网关服务发出请求,如下所示:

添加 awc 箱:

cargo add awc

然后添加转发请求服务

async fn forward_request(req: HttpRequest) -> HttpResponse {
    let target_url = "http://authorization-service"; // Replace with the actual URL of the authorization microservice
    let client = awc::Client::default();

    // Create a new request and copy necessary headers
    let forwarded_req = client
        .request_from(target_url, req.head())
        .no_decompress()
        .insert_header((
            "Authorization",
            req.headers().get("Authorization").unwrap().clone(),
        ));

    // Send the forwarded request and return the response
    let mut response = forwarded_req.send().await.unwrap();
    HttpResponse::build(response.status()).body(response.body().await.unwrap())
}

0
投票

这是因为您没有指定 fetch API 将返回什么类型的数据。

假设您期望返回 JSON 类型,您可以按如下方式编辑它

(async () => {
    let response = await fetch('http://127.0.0.1:8080/auth/restricted/me', {
        method: 'GET',
        headers: {
            'Authorization': `Bearer ${token}`
        }
    });
    const result = response.json()
   
    console.log(result.status);
})();
© www.soinside.com 2019 - 2024. All rights reserved.