background

Wednesday, 18:00.

Xiao Ming twisted slightly sour neck, rubbed rubbed staring at the screen some dry eyes.

Finally busy finished, near to go off work, the whole people also become relaxed.

“The counterparty needs us to provide new service. It will be online next Tuesday. I will send you the demand, which is very simple.”

The product manager sent a message to break the good news.

“I can screw it. Every demand comes right after work.” Xiao Ming could not help but murmur in his heart, but his hands did not stop.

“Okay, let me look at the demand first.”

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

Provide external docking parties with an interface to the new merchant. Keep consistent with the new merchants on the internal console.

It’s really not too difficult. Xiaoming thought about it. Although the new merchants on the internal console were not created by themselves, the interface should be directly reusable and the code should also be reusable.

But I have not done external docking before, I do not know if there are other pits.

It goes live on Tuesday next week, so we need to have the lift test and the test come in on Monday.

Xiao Ming opened the calendar. Today and Wednesday, there are only two days left for the preparation of interface documents, detailed design, coding and self-testing.

It should be enough, but there are all kinds of chores that need to be dealt with, which can reduce your overall productivity.

Ask your colleagues for previous code and documentation.

Looking at the time has exceeded the work time, Xiao Ming sighed.

Interface documentation

Document writing

Thursday, 9:30.

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

However, the external interface is still a little different. Xiaoming added fields such as traceId and requestTime according to his own understanding to facilitate the troubleshooting and positioning of problems.

The basic interface is then written:

Request parameters:

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

Response parameters:

The serial number parameter describe If required instructions
1 respCode The response code is 000000 indicates success; see the response coding enumeration for the rest
2 respDesc The response described is Request time, yyyyMMddHHmmssSSS 17 bit timestamp
3 userId The user id is A 32-bit string that uniquely identifies the user upon successful creation

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

And the basic detailed design documents are also sorted out.

1762 words, Xiao Ming took a look 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, how time flies.

So I booked a conference room at 14:00 in the afternoon, and prepared to go over the documents with the product manager, test manager and project manager.

Document review

Meeting room 14:00.

Xiao Ming came to the meeting room on time, inserted the projector in advance, and waited for everyone’s arrival.

“The request I made yesterday was simple.” “, before anyone asked, the product manager just arrived at the door and walked in smiling.

“Yes, I am.”

Then the project manager and the test walked in.

“Hurry over the requirements document,” said the project manager.

The Ming and Qing Dynasties cleared the throat and spoke about the overall project background. And I went through my detailed design and interface documentation.

In the meantime, the product manager is doing other things, and these details don’t need to be cared about.

Listen to the test more seriously, keep putting forward their own questions, behind the need to verify their own.

“Any other questions?” Xiao Ming kept talking for more than half an hour by himself, which made him feel a bit boring.

“I’m fine,” the test said. “All I care about is when can I get a test?”

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

“That’s fine,” the test replied, and said he had no other questions.

“The document you write is very detailed”, the project manager looked at Xiaoming with slightly approving eyes, “but there is a problem, your interface is not even signed.”

‘Signature, what signature? Xiao Ming was a little confused.

“You don’t even know how to sign an external interface? I still have time to learn.” “, the project manager was clearly disappointed.

“Well, never mind that.” “And the product manager jumped into the conversation.” How about next Tuesday for a simple requirement like that?”

“It should be no problem, as long as the test on time on the line”, the test looked at Xiao Ming.

“Should be no problem”, Xiaoming’s mind is still thinking about the interface signature, “I go back to see the interface signature, adjust the interface.”

Interface signature

Signature role

Xiaoming to check the check, found external interface, security is certainly need to be considered.

In order to ensure the security of data and prevent information from being tampered with, signature is a common way.

Signature implementation

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

(1) Sort all parameters, except CheckValue itself, in alphabetical ascending order by parameter name.

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

(3) After splicing the string, use the key agreed by both parties to conduct MD5 encryption and get the checkValue value

(4) Set the corresponding value to the checkValue attribute

Of course, there may be differences in the implementation of the signature, but both parties can agree.

Signature verification

Knowing how to check is similar.

Repeat steps (1), (2) and (3) above to get the corresponding checkValue.

Then compare with the value passed by the other party. If the value is consistent, the signature verification is passed.

Interface adjustment

After understanding the need for a signature, Xiao Ming added the CheckValue attribute value to the interface document.

And the test and private communication, here, the document is a preliminary end.

Looking at the time has exceeded the work time, Xiao Ming sighed.

Code implementation

v1

Friday at 10:00.

Xiao Ming came to the company began to code, other things to deal with about the same, only a signature implementation problem.

I didn’t think much about it at first, but I realized it as follows:

Public String BuildCheckValue () {public String BuildCheckValue () {public String BuildCheckValue () {public String BuildCheckValue () StringBuilder(); stringBuilder.append(name); stringBuilder.append(password); Return md5util.md5 (StringBuilder.toString ()); return md5util.md5 (String Builder.toString()); }

Of course, being a utilitarian, Xiao Ming is aware of a problem.

There must be similar tools in other projects and you should not duplicate the wheel yourself.

V2 version

Copied a tool class from another application. It looks like this:

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.*; Public class CheckValueUtils {private CheckValueUtils(){} public static String buildCheckValue(Object object) { Class<? > clazz = object.getClass(); FieldMap <String, Field> fieldMap = classutil.getAllFieldMap (clazz); // remove fieldMap.remove("checkValue"); Set<String> fieldNameset = fieldMap.keyset (); List<String> fieldNameList = new ArrayList<>(fieldNameSet); Collections.sort(fieldNameList); StringBuilder = new StringBuilder(); for(String fieldName : fieldNameList) { Object value = ReflectFieldUtil.getValue(fieldName, object); . / / reflection get the value String valueStr = StringUtil objectToString (value, ""); / / stitching stringBuilder. Append (fieldName) append (" = "). Append (valueStr); } //md5 sign return md5util.md5 (StringBuilder.toString ()); }}

In general, it is still very good to use, and their own time is not much, just use it directly.

After all done, is self-testing work, after a step pit, xiao Ming is the entire interface through self-testing.

“In this way, it will be too late for the survey.”

Looking at the time has exceeded the work time, Xiao Ming sighed.

More elegant signing implementation

That’s where the story usually ends.

But Xiao Ming had an idea to keep the story going.

Insufficiency of instrumental methods

The original approach can meet most of the requirements, but it can be cumbersome to adjust.

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

These will cause the original tool method is not available, need to be copied, modified.

Is it possible to implement a more flexible signing tool?

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

Quick start

Maven is introduced into

<plugin> < grouppid >com.github. Houbb </ grouppid > <artifactId>checksum</artifactId> <version>0.0.6</version> </plugin>

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

There are two core annotations involved:

@CheckField represents the information of the fields participating in the checkup. By default, they are all participating in the checkup. Specifies required=false to skip the checkmark.

@CheckValue indicates the field in which the checked-in result is stored. This field needs to be of type String.

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

To get the signature

All of the utility class methods are shown in ChecksumHelper, and the following methods support specifying a secret key.

User user = User.buildUser();

final String checksum = ChecksumHelper.checkValue(user);

This method handles all the fields in the User object that specify @CheckField.

Slotting is performed by specifying the sort, and then the final check result is constructed in combination with the specified encryption policy.

Fill the signature

User user = User.buildUser();

ChecksumHelper.fill(user);

You can default the corresponding checkValue value to the field specified by @checkValue.

Verify the signature

User user = User.buildUser();

boolean isValid = ChecksumHelper.isValid(user);

The current User object is signed, and the result is compared with the user’s own signature.

The bootstrap class

ChecksumBs bootstrap class

For a more flexible scenario, we introduced the Checksumbs boot class based on Fluent-API.

The above configuration is equivalent by default 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();

Configuration instructions

All of the above configurations are flexibly interchangeable, and all implementations support user customization.

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

performance

background

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

Sometimes because of concern about performance, they choose to copy and paste again and again manually.

performance

See BenchmarkTest. Java

This time 100W tests and verifications were carried out, and the time consuming was as follows.

Manual processing time: 2505ms

Annotation processing time: 2927ms

summary

Signature is used in communication with external interfaces to ensure that information is not tampered with.

I hope this tool can help you get off work on time.

I am an old horse, looking forward to the next meeting with you.