use crate::token::AccessToken;
use crate::token_rsa::AccessTokenRsa;
use crate::{idmlogin::get_idm, rbac::get_rbac};
use crate::{Response, RpConfig};
use actix_http::header::HeaderMap;
use actix_web::{error, Error};
use actix_web::{HttpRequest, HttpResponse};
use anyhow::anyhow;
use dashmap::DashMap;
use regex::Regex;
use serde::Serialize;
use std::sync::OnceLock;
use std::{collections::HashMap, fmt::Debug};
#[derive(Default)]
pub struct PermissionMap {
pub pmap: HashMap<&'static str, (&'static str, &'static str)>, pub whitelist: Vec<&'static str>, pub secret: String, pub use_rsa: bool, pub app_name: String, pub use_local: bool, pub config: DashMap<String, String>, }
static PMAP: OnceLock<PermissionMap> = OnceLock::<PermissionMap>::new();
pub fn init_pmap(
whitelist: Vec<&'static str>,
pmap: HashMap<&'static str, (&'static str, &'static str)>,
secret: String,
app_name: String,
use_local: bool,
use_rsa: bool,
) -> &'static PermissionMap {
PMAP.get_or_init(|| PermissionMap {
pmap: pmap,
whitelist: whitelist,
secret: secret,
app_name: app_name,
use_local: use_local,
use_rsa: use_rsa,
config: DashMap::default(),
})
}
pub fn get_pmap() -> &'static PermissionMap {
PMAP.get().unwrap()
}
#[derive(thiserror::Error, Debug)]
pub enum VerifyError {
#[error("Header中无鉴权信息")]
TokenNone, #[error("Header中鉴权信息bearer的格式不对")]
TokenBearerWrong, #[error("rbac_map中缺少`{0}`的RBAC权限配置")]
RbacNone(String), #[error("解析AccessToken鉴权信息失败")]
TokenDecodeErr, #[error("核查所有权限后该用户无对应权限: `{0}`")]
NoPermission(String), }
impl PermissionMap {
pub async fn get_rbac_config(&self) -> RpConfig {
if self.use_local {
return get_rbac().rbac.read().await.clone();
} else {
let app_rpinfo = if let Some(rpinfo) = get_idm().rpinfo.get(&self.app_name) {
rpinfo.value().clone()
} else {
get_rbac().rbac.read().await.clone()
};
app_rpinfo
}
}
pub async fn get_rbac_config_from_map(&self, rbac_key: &String) -> anyhow::Result<RpConfig> {
if let Some(config) = get_rbac().get_rbac_from_map(rbac_key).await {
Ok(config)
} else {
return Err(anyhow!("无法在RBAC-MAP中找到Key-{}相关的配置", rbac_key));
}
}
pub async fn check_token_only(
&self,
req: &HttpRequest,
) -> std::result::Result<AccessToken, VerifyError> {
let (headers, _reqpath) = get_token_and_path(req);
if !headers.contains_key(actix_http::header::AUTHORIZATION) {
return Err(VerifyError::TokenNone);
}
let token = headers
.get(actix_http::header::AUTHORIZATION)
.unwrap()
.to_str()
.unwrap()
.to_string();
if token.len() < 7 {
return Err(VerifyError::TokenBearerWrong);
}
let token = token.split_at(7).1.to_string();
let access = if self.use_rsa {
let access = AccessTokenRsa::decode_token(&token, &self.secret);
if access.is_ok() {
access.unwrap().to_token()
} else {
return Err(VerifyError::TokenDecodeErr);
}
} else {
let access = AccessToken::decode_token(&token, self.secret.as_str());
if access.is_ok() {
access.unwrap()
} else {
return Err(VerifyError::TokenDecodeErr);
}
};
Ok(access)
}
pub async fn check_and_verify(
&self,
req: &HttpRequest,
) -> std::result::Result<AccessToken, VerifyError> {
let (headers, reqpath) = get_token_and_path(req);
if !headers.contains_key(actix_http::header::AUTHORIZATION) {
return Err(VerifyError::TokenNone);
}
let token = headers
.get(actix_http::header::AUTHORIZATION)
.unwrap()
.to_str()
.unwrap()
.to_string();
if token.len() < 7 {
return Err(VerifyError::TokenBearerWrong);
}
let token = token.split_at(7).1.to_string();
let access = if self.use_rsa {
let access = AccessTokenRsa::decode_token(&token, &self.secret);
if access.is_ok() {
access.unwrap().to_token()
} else {
return Err(VerifyError::TokenDecodeErr);
}
} else {
let access = AccessToken::decode_token(&token, self.secret.as_str());
if access.is_ok() {
access.unwrap()
} else {
return Err(VerifyError::TokenDecodeErr);
}
};
if access.is_admin {
return Ok(access);
}
if self.whitelist.contains(&reqpath.as_str()) {
return Ok(access);
}
for each in self.whitelist.iter() {
if let Ok(re) = Regex::new(*each) {
if re.captures(&reqpath).is_some() {
return Ok(access);
}
}
}
let user_account = access.user_account.clone();
let app_rpinfo = self.get_rbac_config().await;
if let Some((page, item)) = self.pmap.get(reqpath.as_str()) {
let check_status = app_rpinfo.check_user_action(
user_account.clone(),
page.to_string(),
item.to_string(),
);
if check_status.0 {
return Ok(access);
}
}
for (each_route, (page, item)) in self.pmap.iter() {
if let Ok(re) = Regex::new(*each_route) {
if re.captures(&reqpath).is_some() {
let check_status = app_rpinfo.check_user_action(
user_account.clone(),
page.to_string(),
item.to_string(),
);
if check_status.0 {
return Ok(access);
}
}
}
}
return Err(VerifyError::NoPermission(user_account.clone()));
}
pub async fn check_and_verify_map(
&self,
req: &HttpRequest,
rbac_key: &String,
) -> std::result::Result<AccessToken, VerifyError> {
let (headers, reqpath) = get_token_and_path(req);
if !headers.contains_key(actix_http::header::AUTHORIZATION) {
return Err(VerifyError::TokenNone);
}
let token = headers
.get(actix_http::header::AUTHORIZATION)
.unwrap()
.to_str()
.unwrap()
.to_string();
if token.len() < 7 {
return Err(VerifyError::TokenBearerWrong);
}
let token = token.split_at(7).1.to_string();
let access = if self.use_rsa {
let access = AccessTokenRsa::decode_token(&token, &self.secret);
if access.is_ok() {
access.unwrap().to_token()
} else {
return Err(VerifyError::TokenDecodeErr);
}
} else {
let access = AccessToken::decode_token(&token, self.secret.as_str());
if access.is_ok() {
access.unwrap()
} else {
return Err(VerifyError::TokenDecodeErr);
}
};
if access.is_admin {
return Ok(access);
}
if self.whitelist.contains(&reqpath.as_str()) {
return Ok(access);
}
for each in self.whitelist.iter() {
if let Ok(re) = Regex::new(*each) {
if re.captures(&reqpath).is_some() {
return Ok(access);
}
}
}
let user_account = access.user_account.clone();
let app_rpinfo = self.get_rbac_config_from_map(rbac_key).await;
if app_rpinfo.is_err() {
return Err(VerifyError::RbacNone(rbac_key.clone()));
}
let app_rpinfo = app_rpinfo.unwrap();
if let Some((page, item)) = self.pmap.get(reqpath.as_str()) {
let check_status = app_rpinfo.check_user_action(
user_account.clone(),
page.to_string(),
item.to_string(),
);
if check_status.0 {
return Ok(access);
}
}
for (each_route, (page, item)) in self.pmap.iter() {
if let Ok(re) = Regex::new(*each_route) {
if re.captures(&reqpath).is_some() {
let check_status = app_rpinfo.check_user_action(
user_account.clone(),
page.to_string(),
item.to_string(),
);
if check_status.0 {
return Ok(access);
}
}
}
}
return Err(VerifyError::NoPermission(user_account.clone()));
}
}
pub fn get_token_and_path(req: &HttpRequest) -> (HeaderMap, String) {
let headers = req.headers();
let reqpath = format!("{} {}", req.method(), req.path());
(headers.clone(), reqpath)
}
pub async fn check_token_only<T: Serialize + Debug>(
req: &HttpRequest,
) -> Result<AccessToken, Error> {
let access = get_pmap().check_token_only(&req).await.map_err(|e| {
tracing::error!("token check error: {:?}", e);
let rsp = get_err_resp::<T>(&e);
error::InternalError::from_response("", rsp)
})?;
Ok(access)
}
pub async fn check_and_verify<T: Serialize + Debug>(
req: &HttpRequest,
) -> Result<AccessToken, Error> {
let access = get_pmap().check_and_verify(&req).await.map_err(|e| {
tracing::error!("token permission error: {:?}", e);
let rsp = get_err_resp::<T>(&e);
error::InternalError::from_response("", rsp)
})?;
Ok(access)
}
pub async fn check_and_verify_map<T: Serialize + Debug>(
req: &HttpRequest,
rbac_key: &String,
) -> Result<AccessToken, Error> {
let access = get_pmap()
.check_and_verify_map(&req, rbac_key)
.await
.map_err(|e| {
tracing::error!("token permission error: {:?}", e);
let rsp = get_err_resp::<T>(&e);
error::InternalError::from_response("", rsp)
})?;
Ok(access)
}
pub fn create_error<T: Serialize + Debug>(e: anyhow::Error, err: &str) -> Error {
tracing::error!("error of {}:{:?}", err, e);
let rsp = Response::<T>::internal_error(format!("{}:{:?}", err, e).as_str()).finished();
error::InternalError::from_response("", rsp).into()
}
fn get_err_resp<T: Serialize + Debug>(err: &VerifyError) -> HttpResponse {
match err {
VerifyError::TokenNone => {
Response::<T>::internal_error(format!("Token缺少字段: {:?}", err).as_str()).finished()
}
VerifyError::TokenBearerWrong => {
Response::<T>::internal_error(format!("Token格式错误: {:?}", err).as_str()).finished()
}
VerifyError::RbacNone(_) => {
Response::<T>::internal_error(format!("Token权限为空: {:?}", err).as_str()).finished()
}
VerifyError::TokenDecodeErr => {
Response::<T>::token_expired(format!("Token解析错误: {:?}", err).as_str()).finished()
}
VerifyError::NoPermission(_) => {
Response::<T>::forbidden(format!("Token权限不足: {:?}", err).as_str()).finished()
}
}
}