| | |
| | | import feign.RequestTemplate; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.Map; |
| | | import java.util.UUID; |
| | | |
| | | /** Spring 会把该 RequestInterceptor 应用于管理端全部 Feign 客户端。 */ |
| | | /** 仅透传敏感数据访问所需的内部标识;Feign 调用不是用户操作,不写审计日志。 */ |
| | | @Component |
| | | public class ManagementFeignAuditInterceptor implements RequestInterceptor { |
| | | @Resource private ManagementAuditWriter auditWriter; |
| | | |
| | | @Override |
| | | public void apply(RequestTemplate template) { |
| | | try { |
| | | Map<String, Object> audit = new HashMap<String, Object>(); |
| | | String url = template.url(); |
| | | if (url != null && url.startsWith("/internal/sensitive/") |
| | | && UserExt.getUser() != null && "admin".equalsIgnoreCase(UserExt.getUser().getAccount())) { |
| | | template.header("X-Internal-Sensitive-Access", "true"); |
| | | } |
| | | audit.put("traceId", UUID.randomUUID().toString().replace("-", "")); |
| | | audit.put("sourceService", "mb-cloud-management"); |
| | | audit.put("sourceType", "FEIGN"); |
| | | audit.put("operationType", "FEIGN_CALL"); |
| | | audit.put("riskLevel", riskLevel(url)); |
| | | audit.put("operationName", template.feignTarget() == null ? "Feign调用" : template.feignTarget().name()); |
| | | audit.put("requestMethod", template.method()); |
| | | audit.put("requestUri", url); |
| | | audit.put("requestParams", template.body() == null ? null : "bodyBytes=" + template.body().length); |
| | | audit.put("userId", UserExt.getUser() == null ? null : UserExt.getUser().getId()); |
| | | audit.put("userAccount", UserExt.getUser() == null ? null : UserExt.getUser().getAccount()); |
| | | audit.put("result", "REQUESTED"); |
| | | audit.put("createdAt", new Date()); |
| | | auditWriter.append(audit); |
| | | } catch (Exception ignored) { |
| | | // 审计异常绝不能阻塞原 Feign 调用。 |
| | | String url = template.url(); |
| | | if (url != null && url.startsWith("/internal/sensitive/") |
| | | && UserExt.getUser() != null && "admin".equalsIgnoreCase(UserExt.getUser().getAccount())) { |
| | | template.header("X-Internal-Sensitive-Access", "true"); |
| | | } |
| | | } |
| | | |
| | | private String riskLevel(String url) { |
| | | String value = url == null ? "" : url.toLowerCase(); |
| | | return value.matches(".*(ticket|payment|finance|refund|withdraw|balance|status|state).*") ? "CRITICAL" : "NORMAL"; |
| | | } |
| | | } |