You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RestTemplate日志脱敏与Java反射提取完整类名的技术咨询

Hey there! Let's break down your two questions and work through better solutions for each one.


1. Hiding Username/Password in RestTemplate Logs

When using RestTemplate to handle login requests and subsequent calls with a webToken, masking sensitive credentials in logs is crucial for security. Here are two reliable approaches:

Option 1: Custom ClientHttpRequestInterceptor

Create an interceptor that detects login requests, masks the sensitive fields in the request body before logging, then proceeds with the request:

import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

public class SensitiveDataMaskingInterceptor implements ClientHttpRequestInterceptor {
    private static final Logger logger = LoggerFactory.getLogger(SensitiveDataMaskingInterceptor.class);

    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        String requestUri = request.getURI().toString();
        // Target only login requests
        if (requestUri.contains("/login")) {
            String originalBody = new String(body, StandardCharsets.UTF_8);
            // Mask username and password (adjust regex if your request format differs)
            String maskedBody = originalBody.replaceAll("\"username\":\"[^\"]*\"", "\"username\":\"***\"")
                                            .replaceAll("\"password\":\"[^\"]*\"", "\"password\":\"***\"");
            logger.info("Sending login request to {} with masked body: {}", requestUri, maskedBody);
            return execution.execute(request, maskedBody.getBytes(StandardCharsets.UTF_8));
        } else {
            // Log non-login requests normally
            logger.info("Sending request to {} with body: {}", requestUri, new String(body, StandardCharsets.UTF_8));
            return execution.execute(request, body);
        }
    }
}

Add this interceptor to your RestTemplate:

RestTemplate restTemplate = new RestTemplate();
restTemplate.getInterceptors().add(new SensitiveDataMaskingInterceptor());

Option 2: Logback/SLF4J Custom Converter (Spring Boot)

If you're using Logback, you can create a custom converter to filter sensitive data directly in log outputs. Add this to your logback.xml:

<conversionRule conversionWord="maskedBody" converterClass="com.yourpackage.SensitiveDataConverter"/>

Then implement the converter:

import ch.qos.logback.classic.pattern.ClassicConverter;
import ch.qos.logback.classic.spi.ILoggingEvent;

public class SensitiveDataConverter extends ClassicConverter {
    @Override
    public String convert(ILoggingEvent event) {
        String message = event.getMessage();
        if (message.contains("/login")) {
            return message.replaceAll("\"username\":\"[^\"]*\"", "\"username\":\"***\"")
                          .replaceAll("\"password\":\"[^\"]*\"", "\"password\":\"***\"");
        }
        return message;
    }
}

Update your log pattern to use %maskedBody instead of the raw message.


2. Better Reflection Type Check & Full Class Name Extraction

Looking at your TypeCheck code, the core issue is that you're passing a Class object to a method expecting an Object, then using instanceof incorrectly (you're checking if the Class instance is an Animal, which it never will be). Here's how to fix and optimize this:

Fix 1: Correct Method Parameter Type

Since you're passing animal.getClass() (a Class object), change the method parameter to Class<?> for clarity:

package reflection;

public class TypeCheck {
    public static void main(String[] args) {
        Object animal = new Animal("Elephant");
        classType(animal.getClass()); // Now works correctly
        // Output - Matched reflection.Animal
    }

    private static void classType(Class<?> type) {
        // Check if the type is Animal or a subclass
        if (Animal.class.isAssignableFrom(type)) {
            // getName() returns the full qualified class name (including package)
            System.out.println("Matched " + type.getName());
        } else {
            System.out.println("Unmatched " + type.getName());
        }
    }
}

class Animal {
    String name;
    public Animal(String name) {
        super();
        this.name = name;
    }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

type.getName() will give you exactly the full class name you need (reflection.Animal), and isAssignableFrom() is the proper way to check class hierarchy in reflection.

Fix 2: Handle Both Instance and Class Inputs

If you need the method to accept either an Animal instance or its Class object, adjust the method to detect the input type first:

private static void classType(Object input) {
    Class<?> clazz;
    if (input instanceof Class) {
        clazz = (Class<?>) input;
    } else {
        clazz = input.getClass(); // Get class from the instance
    }

    if (Animal.class.isAssignableFrom(clazz)) {
        System.out.println("Matched " + clazz.getName());
    } else {
        System.out.println("Unmatched " + clazz.getName());
    }
}

This way, both classType(animal) and classType(animal.getClass()) will work correctly.

Why Your Original Approach Is Risky

Using type.toString().contains("Animal") is fragile because:

  • It can false-positive match other classes named Animal in different packages.
  • Code obfuscation (common in production) will break this check.
  • It's unclear to other developers what you're trying to validate.

内容的提问来源于stack exchange,提问作者Ashish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 20:27:29