SpringBoot_Secret
第一步
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.7.22</version>
    </dependency>
</dependencies>
第二步
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private Integer id;
    private String name;
    private String sex;
}
第三步
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Signature {
}
第四步
public class SignatureUtils {
    private static final String DEFAULT_SECRET = "1qaz@WSX#$%&";
    public static String sign(String body, Map<String, String[]> params, String[] paths) {
        StringBuilder sb = new StringBuilder();
        if (CharSequenceUtil.isNotBlank(body)) {
            sb.append(body).append('#');
        }
        if (!CollectionUtils.isEmpty(params)) {
            params.entrySet()
                    .stream()
                    .sorted(Map.Entry.comparingByKey())
                    .forEach(paramEntry -> {
                        String paramValue = String.join(",", Arrays.stream(paramEntry.getValue()).sorted().toArray(String[]::new));
                        sb.append(paramEntry.getKey()).append("=").append(paramValue).append('#');
                    });
        }
        if (ArrayUtil.isNotEmpty(paths)) {
            String pathValues = String.join(",", Arrays.stream(paths).sorted().toArray(String[]::new));
            sb.append(pathValues);
        }
        return SecureUtil.sha256(String.join("#", DEFAULT_SECRET, sb.toString()));
    }
}
第五步
@Aspect
@Component
public class SignatureAspect {
    private static final String SIGN_HEADER = "X-SIGN";
    @Pointcut("execution(@com.example.springbootsecret.comment.Signature * *(..))")
    private void verifySignPointCut() {
    }
    @Before("verifySignPointCut()")
    public void verify() {
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String sign = request.getHeader(SIGN_HEADER);
        
        if (CharSequenceUtil.isBlank(sign)) {
            throw new RuntimeException("no signature in header: " + SIGN_HEADER);
        }
        
        try {
            String generatedSign = generatedSignature(request);
            if (!sign.equals(generatedSign)) {
                throw new RuntimeException("invalid signature");
            }
        } catch (Throwable throwable) {
            throw new RuntimeException("invalid signature");
        }
    }
    private String generatedSignature(HttpServletRequest request) throws IOException {
        
        String bodyParam = null;
        if (request instanceof ContentCachingRequestWrapper) {
            bodyParam = new String(((ContentCachingRequestWrapper) request).getContentAsByteArray(), StandardCharsets.UTF_8);
        }
        
        Map<String, String[]> requestParameterMap = request.getParameterMap();
        
        String[] paths = null;
        ServletWebRequest webRequest = new ServletWebRequest(request, null);
        Map<String, String> uriTemplateVars = (Map<String, String>) webRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST);
        if (!CollectionUtils.isEmpty(uriTemplateVars)) {
            paths = uriTemplateVars.values().toArray(new String[0]);
        }
        return SignatureUtils.sign(bodyParam, requestParameterMap, paths);
    }
}
第六步
public class RequestFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
        boolean isFirstRequest = !isAsyncDispatch(request);
        HttpServletRequest requestWrapper = request;
        if (isFirstRequest && !(request instanceof ContentCachingRequestWrapper)) {
            requestWrapper = new ContentCachingRequestWrapper(request);
        }
        try {
            filterChain.doFilter(requestWrapper, response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
第七步
@Configuration
public class SignatureConfig {
    @Bean
    public RequestFilter requestCachingFilter() {
        return new RequestFilter();
    }
    @Bean
    public FilterRegistrationBean<?> requestCachingFilterRegistration(RequestFilter requestCachingFilter) {
        FilterRegistrationBean<?> bean = new FilterRegistrationBean<>(requestCachingFilter);
        bean.setOrder(1);
        return bean;
    }
}
第八步
@RestController
@RequestMapping("/user")
public class UserController {
    @Signature 
    @PostMapping("/{id}")
    public String myController(@PathVariable String id, @RequestParam String name, @RequestBody User user) {
        return String.join(",", id, name, user.toString());
    }
}