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.