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());
}
}