background

Wednesday, 18:00.

Xiaoming twisted his sour neck and rubbed his dry eyes staring at the screen.

Finally finished busy, approaching to go off work, the whole heart has become relaxed.

“On the receiving side we need to provide a new service, next Tuesday online, demand I send you, very simple.”

A message from the product manager broke the good news.

“Screw me, every demand is coming at the end of the day.” Xiao Ming could not help but whisper in the heart, but the hand can not stop.

“Ok, LET me look at the demand first.”

After replying, I clicked on the requirements document, which was really simple.

Provides an interface for external counterparties to add merchants. Keep consistent with the new merchants in the internal console.Copy the code

It is not too difficult, Xiao Ming thought, although the internal console new merchant is not their own, but the interface should be able to directly reuse, code should also be able to reuse.

However, I haven’t done external docking before, so I don’t know if there are other pits.

It’s going to be available next Tuesday, so next Monday you need to get the beta, get the beta involved.

Xiaoming turned on the calendar, today is Wednesday, his interface documentation, detailed design, coding and self-testing time is only two days.

Should have been sufficient, but usually there will be a variety of work chores need to deal with, will reduce the overall work efficiency.

Ask colleagues for old code and documentation first.

Seeing that it was already past the end of the day, Xiao Ming sighed.

Interface documentation

Document writing

Thursday, 9:30.

Xiaoming came to the company began to deal with the preparation of interface documents, with the previous document basis, write up or very fast.

However, the external interface is still somewhat different. Xiaoming added traceId, requestTime and other fields according to his own understanding to facilitate troubleshooting and locating problems.

The basic interface is then written:

Request parameters:

The serial number parameter describe If required instructions
1 traceId A unique identifier is A 32-bit string used to uniquely locate a request
2 requestTime Request parameters is Request time, yyyyMMddHHmmssSSS 17-bit timestamp
3 username The user name is The longest string is 64 characters
4 password password is A string of up to 128 characters, encrypted by MD5
5 address address no A string of up to 128 characters

Response parameters:

The serial number parameter describe If required instructions
1 respCode The response code is 000000 indicates success, for others, see enumeration of response encoding
2 respDesc The response described is Request time, yyyyMMddHHmmssSSS 17-bit timestamp
3 userId The user id is A string of 32 characters that uniquely identifies a user after a successful creation

Xiaoming wrote down in detail the request mode of the whole interface, matters needing attention, as well as the corresponding enumeration values.

I also organized the basic detailed design documents.

1762 words, Xiao Ming looked at the total number of words, bitter smile.

This document, of course, is not as concise as the requirements document.

When I looked up, it was already 11:30. Boy, time flies.

So I booked a meeting room at 14:00 PM and prepared to go over documents with product manager, test manager and project manager.

Document review

Conference room 14:00.

Xiao Ming arrived at the meeting room on time, plugged in the projector in advance, and waited for everyone’s arrival.

“What I asked for yesterday was simple.” The product manager just arrived at the door and walked in with a smile.

“Yes, it’s fine.”

Then the project manager and the test come in.

“Hurry up with the requirements document,” said the project manager.

Little Ming qing cleared his throat and spoke about the overall project background. And put their own detailed design and interface documents over.

While the product manager is busy doing other things, these details don’t need to be addressed.

Listen to the test more seriously, constantly put forward their own questions, behind the need for their own verification.

“Any other questions?” Xiao Ming himself kept talking for more than half an hour, feeling a little boring.

“I have no more questions,” said the tester. “All I care about is when can I take the test?”

“Next Monday,” Mindy paused. “I don’t think I can start coding until after.”

“That’s fine,” the test replied, adding that he had no further questions.

“Your document is quite detailed”, the project manager looked at Xiao Ming with slightly approving eyes, “but there is a problem, your interface does not even have a signature.”

“Signature, what signature?” Xiao Ming is confused.

“You don’t even know the outgoing interface signature? I have time to learn.” The project manager was clearly disappointed.

“Well, that’s enough.” “The product manager then joined the conversation.” Is this simple requirement ok for next Tuesday?”

“There should be no problem, as long as you take the test on time.” The test looked at Xiao Ming.

“There should be no problem.” Xiao Ming was still thinking about the interface signature. “I will check the interface signature and adjust the interface.”

Interface signature

Signature role

Xiao Ming went to check and found that the external interface, security must be considered.

To ensure data security and prevent information from being tampered with, signature is a common method.

Signature implementation

There are many ways to achieve, the more common way:

(1) All parameters, except checkValue itself, are sorted alphabetically by parameter name.

(2) The sorted parameters are spliced into strings according to the way of parameters and values

(3) Md5 encryption is performed on the concatenated string using the key agreed by both parties to obtain checkValue

(4) Set the corresponding value to the checkValue property

Of course, there may be differences in the implementation of the signature, but the two sides should be consistent.

Signature verification

Know how to sign, check is similar.

Repeat steps (1) (2) (3) above to obtain the corresponding checkValue.

Then, the signature is compared with the value transmitted by the peer. If the value is the same, the signature is verified successfully.

Interface adjustment

After understanding the necessity of signatures, Ming added the checkValue attribute value to the interface document.

And a private communication with the test, at this point, the documentation is preliminary.

Seeing that it was already past the end of the day, Xiao Ming sighed.

Code implementation

v1

Friday, 10:00.

Xiao Ming came to the company began to code, other things almost after the processing, there is a signature implementation problem.

At first, I didn’t think much about it, but implemented it as follows:

/** * Manually build the verification result *@returnResults *@sinceHundreds * /
public String buildCheckValue(a) {
    StringBuilder stringBuilder = new StringBuilder();
    stringBuilder.append(name);
    stringBuilder.append(password);
    // A bunch of other attributes
    return Md5Util.md5(stringBuilder.toString());
}
Copy the code

Of course, as a conservationist, Ming was aware of a problem.

There must be similar tool classes in other projects, so you shouldn’t duplicate the wheel.

V2 version

Copy a utility class from another application. The implementation is as follows:

import com.github.houbb.heaven.util.lang.StringUtil;
import com.github.houbb.heaven.util.lang.reflect.ClassUtil;
import com.github.houbb.heaven.util.lang.reflect.ReflectFieldUtil;
import com.github.houbb.heaven.util.secrect.Md5Util;

import java.lang.reflect.Field;
import java.util.*;

/ * * *@author binbin.hou
 * @since1.0.0 * /
public class CheckValueUtils {

    private CheckValueUtils(a){}

    public static String buildCheckValue(Object object) { Class<? > clazz = object.getClass();// Get the fieldMap for all fields
        Map<String, Field> fieldMap = ClassUtil.getAllFieldMap(clazz);

        // Remove the checkValue name
        fieldMap.remove("checkValue");

        // Sort the fields by name
        Set<String> fieldNameSet = fieldMap.keySet();
        List<String> fieldNameList = new ArrayList<>(fieldNameSet);
        Collections.sort(fieldNameList);

        // Reflection gets all string values
        StringBuilder stringBuilder = new StringBuilder();
        for(String fieldName : fieldNameList) {
            Object value = ReflectFieldUtil.getValue(fieldName, object);
            // reflection gets the value
            String valueStr = StringUtil.objectToString(value, "");

            / / stitching
            stringBuilder.append(fieldName).append("=").append(valueStr);
        }


        / / the signature of the md5
        returnMd5Util.md5(stringBuilder.toString()); }}Copy the code

Generally speaking, it is still very easy to use, and their time is not much, it is good to use directly.

After all done, is the self-test work, after a step pit, Xiaoming is the whole interface self-test through.

“In this way, it’s not too late for the test.”

Seeing that it was already past the end of the day, Xiao Ming sighed.

More elegant signing implementation

Normally, that’s where the story ends.

But an idea from Xiao Ming keeps the story going.

Deficiencies in the tool approach

The original method basically meets most of the requirements, but it can become cumbersome to adjust.

For example, if some very large fields are not checked, the name of the signed section is not checkValue, but changed to sign, adjust the way the fields are sorted, etc.

All these will lead to the original tool method is not available, need to copy, modify.

Is it possible to implement a more flexible checker tool?

The answer is yes, Xiao Ming spent 2 days over the weekend to implement a checkmark tool.

Quick start

Maven is introduced into

<plugin>
    <groupId>com.github.houbb</groupId>
    <artifactId>checksum</artifactId>
    <version>0.0.6</version>
</plugin>
Copy the code

Pojo object

  • User.java
public class User {

    @CheckField
    private String name;

    private String password;

    @CheckField(required = false)
    private String address;

    @CheckValue
    private String checksum;

    //Getter & Setter
    //toString()
}
Copy the code

There are two core notes:

@checkfield Indicates the field information that is checked. By default, the field information is checked. Specifying required=false skips the check-in.

@checkValue Indicates the field that stores the checkered result. The field type must be String.

Later, a String and different types of conversion implementation will be added to expand the application scenarios.

To get the signature

See ChecksumHelper for all utility class methods, and the following methods support specifying secret keys.

User user = User.buildUser();

final String checksum = ChecksumHelper.checkValue(user);
Copy the code

This method processes all the @checkfield fields in the User object,

The final check result is constructed by combining the specified encryption policy with the specified collation.

Fill the signature

User user = User.buildUser();

ChecksumHelper.fill(user);
Copy the code

The corresponding checkValue can be populated by default on the field specified by @checkValue.

Verify the signature

User user = User.buildUser();

boolean isValid = ChecksumHelper.isValid(user);
Copy the code

The current User object is appended and the result is compared to the signature of the user itself.

The bootstrap class

ChecksumBs bootstrap class

To meet more flexible scenarios, we introduce ChecksumBs bootstrap class based on Fluent-API.

The default configuration above is equivalent to:

final String checksum = ChecksumBs
        .newInstance()
        .target(user)
        .charset("UTF-8")
        .checkSum(new DefaultChecksum())
        .sort(Sorts.quick())
        .hash(Hashes.md5())
        .times(1)
        .salt(null)
        .checkFieldListCache(new CheckFieldListCache())
        .checkValueCache(new CheckValueCache())
        .checkValue();
Copy the code

Configuration instructions

All of the above configurations are flexible and all implementations support user customization.

attribute instructions
target Object to be signed
charset coding
checkSum Specific sign implementation
sort Field sorting strategy
hash String encryption HASH policy
salt Encrypt the corresponding salt value
times Number of encryptions
checkFieldListCache Cache implementation of the segment to be signed
checkValueCache Caching implementation of signature fields

performance

background

Every time we talk about reflection the first response is convenience, the second response is performance.

Sometimes because of concerns about performance, and choose to manually copy and paste.

performance

See BenchmarkTest. Java

The 100W test verification takes the following time:

Manual processing time: 2505ms

Annotation processing time: 2927ms

summary

Signature During communication with external interfaces, the signature prevents information from being tampered with.

Hopefully this tool will help you get out of work on time.

I am old ma, looking forward to meeting with you next time.