This is the sixth day of my participation in the November Gwen Challenge. See details: The Last Gwen Challenge 2021.

background

The thing is, I am currently participating in the construction of XXXX project, and I need to connect with a third party. Several asynchronous notifications exist on the peer interface. For the security of the interface, check the parameters of the interface.

In order to facilitate the processing of the returned parameters of the asynchronous notification, colleague Z proposed to encapsulate the verification function uniformly, and then we only need to pay attention to our own business logic.

Z colleague’s solution

Colleague Z chose the “custom parameter parser” solution, let’s look at the code.

Custom annotations

Define a method in custom annotations: whether check is enabled, default check.

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface RsaVerify {
    
    /** * Whether to enable the check function, the default check */
    boolean verifySign(a) default true;
}
Copy the code

Custom method parameter resolver

Create a custom parameter parser RsaVerifyArgumentResolver HandlerMethodArgumentResolver interface is implemented, and implement method of inside.

  1. SupportsParameter: This method is used to determine whether the request interface needs to resolve arguments, return true if required, and then call the resolveArgument method below, or return false if not.
  2. ResolveArgument: The actual parsing method that parses the parameter values in the request into some kind of object.
    • Parameter Specifies the method parameter to parse
    • MavContainer The ModelAndViewContainer of the current request (which provides access to the model for the request)
    • WebRequest Current request
    • WebDataBinderFactory The factory used to create the WebDataBinder
@AllArgsConstructor
@Component
public class RsaVerifyArgumentResolver implements HandlerMethodArgumentResolver {

    private final SecurityService securityService;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RsaVerify.class);
    }

    
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        RsaVerify parameterAnnotation = parameter.getParameterAnnotation(RsaVerify.class);
        if(! parameterAnnotation.verifySign()) {return mavContainer.getModel();
        }
        
        // Process the argument and check the logic.// Returns the processed entity class parameter
        return ObjectMapperFactory
                .getDateTimeObjectMapper("yyyyMMddHHmmss") .readValue(StringUtil.queryParamsToJson(sb.toString()), parameter.getParameterType()); }}Copy the code

Creating a Configuration Class

Create a configuration class PayTenantWebConfig that implements the WebMvcConfigurer interface and adds a custom method parameter parser to the configuration class.

@Configuration
@AllArgsConstructor
public class PayTenantWebConfig implements WebMvcConfigurer {

    private final RsaVerifyArgumentResolver rsaVerifyArgumentResolver;
    
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(rsaVerifyArgumentResolver); }}Copy the code

This completes the foundation for a custom parameter parser solution, which we’ll explain how to use in the next section. If you have different opinions or better idea, welcome to contact AH Q, add AH Q can join the technical exchange group to participate in the discussion!