The author has been engaged in the field of mobile client development for many years, and at the same time, has been paying attention to and studying the server development technology. Front-end and back-end separation techniques have been discussed and practiced for many years. In fact, since the birth of mobile development, it is natural to separate the front and back end architecture, because it involves the communication of front and back end data, so we will use an intermediate data format to complete the front and back end data docking, the docking process mainly includes data packaging, transmission and analysis. Before Json, we used XML as the data encapsulation format. With the rise of restful architecture style, JSON is more and more widely used. At present, XML and WEBService based on SOAP service are hardly found in enterprise development. However, regardless of restful/ JSON style or SOAP/XML architecture, data transfer is stateless, and data requests do not need to rely on client or server storage technologies such as cookies or sessions.

What problems can dynamic tokens solve

  • Can resolve the issue of service invocation user invocation permissions

As we all know, the stateless nature of the publishing of a server API means that any of its interface methods can be called by a client in any order. If a client is making a malicious call to steal sensitive data, we usually add user identity information, such as username and password, to the pass parameters of the call interface. If each API request carries a username and password, not to mention the risk of exposing user account information, it is also business-neutral for the service API from a design point of view, violating the separation of concerns in programming. If the API’s permission validation mechanism changes in the future, the cost of maintaining the changes can be very high.

  • The timeliness of service invocations can be addressed

In fact, the timeliness issue also includes the security issue. Usually, when we design the token, we will give the token the validity period at the same time. After this expiration date, the token is no longer valid, and it is not successful to entrap the token to retrieve API data. Some people say, can we set the token to have no expiration date? Let’s think about it. If a token is valid forever, the longer it lasts, the higher the risk of disclosure of that token. It’s a linear increase. If someone gets this token in the future, he or she has permanent access to the API, which is obviously not appropriate. For example, if we set a token to expire at 2 hours, even if the token is disclosed within 2 hours, then the API call permission is only within 2 hours.

  • Can solve the user identity transfer problem

In traditional API requests, obtaining user data generally relies on passing user identity, such as adding the user ID field to the parameter. Wouldn’t it be nice if we removed this field from the parameters to also get the user’s data? With token, we can do the same. Generally, the user ID is encapsulated in the token for encryption. When used, the token is resolved to retrieve user data. There are many implementation-level approaches to passing API methods, which will be covered in the following sections.

The design of the token

Several issues need to be considered, namely when the token is generated, the basic composition of the token and the encryption and decryption of the token.

  • When tokens are generated

The system login entry is used as the key point for token generation. Users generally use the user name/password, mobile phone number/verification code to log in, which can confirm the validity of the user identity.

  • The constitution of the token

Generally contains user identity information, expiration date, production date.

  • Token encryption and decryption

Using AES asymmetric encryption token, the encryption and decryption of token will only be carried out on the server side, and it is very difficult to crack the token without the private key being leaked.

  • The token validation

Verify the validity of the token first, and determine whether the token is illegal if there is a problem with token resolution. Decrypt the token using the private key, add the generated timestamp and validity period and compare them with the current timestamp. If the time is larger than the current time, the token is valid. In this process, we usually check the request calling API through the filter, so we need to define which API path or method needs to be executed token validity verification.

  • Token passing

When the client requests the API service, the token is added to the HTTP request header and passed as authration.

The key code

Token.java

/ * * *@author liyc
 * @dateDecember 8, 2017 3:17:02 PM *@description* / token objects
public class Token {
	
	String userid;
	
	Long timestamp;
	
	Long period;
	
	public Token(String userid, Long timestamp, Long period) {
		super(a);this.userid = userid;
		this.timestamp = timestamp;
		this.period = period;
	}

	public String getUserid(a) {
		return userid;
	}

	public void setUserid(String userid) {
		this.userid = userid;
	}

	public Long getTimestamp(a) {
		return timestamp;
	}

	public void setTimestamp(Long timestamp) {
		this.timestamp = timestamp;
	}

	public Long getPeriod(a) {
		return period;
	}

	public void setPeriod(Long period) {
		this.period = period;
	}

	@Override
	public String toString(a) {
		return this.userid+";"+timestamp+";"+period; }}Copy the code

TokenMaker.java


/ * * *@author liyc
 * @dateDecember 8, 2017 3:18:21 PM *@descriptionResponsible for token generation, validity verification, parsing */
public class TokenMaker {

	/** * generates a new token **@param token
	 * @param secretKey
	 * @return
	 * @throws TokenException 
	 */
	public static String newToken(Token token, String secretKey) throws TokenException {
		try {
			byte[] b = AEScrypto.encrypt(token.toString(), secretKey);
			String result = Base64.encodeBase64String(b);
			return result;
		} catch (Exception e) {
			throw newTokenException(); }}/** * parse token **@param tokenStr
	 * @param password
	 * @return
	 * @throws TokenException 
	 */
	public static Token resolve(String tokenStr, String password) throws TokenException  {
		try {
			byte[] origionResult = Base64.decodeBase64(tokenStr);
			byte[] decryResult = AEScrypto.decrypt(origionResult, password);
			String origionStr = new String(decryResult);
			String[] ss = origionStr.split(";");
			Token token = new Token(ss[0], Long.parseLong(ss[1]), Long.parseLong(ss[2]));
			return token;
		} catch (Exception e) {
			throw newTokenException(); }}/** * Check whether the token is valid **@param tokenStr
	 * @param password
	 * @return
	 * @throws TokenException 
	 */
	public static boolean isLegal(String tokenStr, String password) throws TokenException {
		Token token = resolve(tokenStr, password);
		long nowTimeStamp = new Date().getTime();
		long endTimeStamp = token.getTimestamp() + token.getPeriod() * 1000;
		returnendTimeStamp > nowTimeStamp; }}Copy the code