我试图从本地主机上运行的 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 授权之外没有说明太多内容,这要么意味着获取令牌时出现问题,要么令牌在某些情况下被修改点。
编辑:从标题中删除了内容类型
看来我已经明白为什么会出现问题,在我的网关服务中,我正在重定向我的所有请求,如下所示:
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())
}
这是因为您没有指定 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);
})();