Skip to content

Instantly share code, notes, and snippets.

@medusar
Forked from caoxudong/TokenGenerator.java
Created July 2, 2018 07:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save medusar/e0643078b852348c62da7b2bd9778cf6 to your computer and use it in GitHub Desktop.
Save medusar/e0643078b852348c62da7b2bd9778cf6 to your computer and use it in GitHub Desktop.
tomcat中生成JSESSIONID的代码
package com.meiliao.ops.utils.security;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.security.crypto.codec.Base64;
/**
* token的生成方式参考tomcat中对JSESSIONID的计算
* <a href="https://github.com/caoxudong/tomcat/blob/dev/java/org/apache/catalina/util/StandardSessionIdGenerator.java">
* https://github.com/caoxudong/tomcat/blob/dev/java/org/apache/catalina/
* util/StandardSessionIdGenerator.java</a>
*
* @author caoxudong
* @since 0.1.0
*/
public class TokenGenerator {
private static Logger log = LogManager.getLogger(TokenGenerator.class);
private static Map<String, String> infoMap = new HashMap<String, String>();
static {
infoMap.put("sessionIdGeneratorBase.createRandom", "Creation of SecureRandom instance for session ID generation using [{0}] took [{1}] milliseconds.");
infoMap.put("sessionIdGeneratorBase.random", "Exception initializing random number generator of class [{0}]. Falling back to java.secure.SecureRandom");
infoMap.put("sessionIdGeneratorBase.randomAlgorithm", "Exception initializing random number generator using algorithm [{0}]");
infoMap.put("sessionIdGeneratorBase.randomProvider", "Exception initializing random number generator using provider [{0}]");
}
/**
* Queue of random number generator objects to be used when creating session
* identifiers. If the queue is empty when a random number generator is
* required, a new random number generator object is created. This is
* designed this way since random number generators use a sync to make them
* thread-safe and the sync makes using a a single object slow(er).
*/
private static Queue<SecureRandom> randoms = new ConcurrentLinkedQueue<>();
private static int sessionIdLength = 32;
private static String secureRandomClass = null;
private static String secureRandomProvider = null;
private static String secureRandomAlgorithm = "SHA1PRNG";
public static String generate(String a) {
String content = a;
byte[] tokenBytes = Base64.encode(content.getBytes());
return new String(tokenBytes);
}
public static String generateToken() {
int sessionIdLength = getSessionIdLength();
byte random[] = new byte[sessionIdLength];
// Render the result as a String of hexadecimal digits
// Start with enough space for sessionIdLength and medium route size
StringBuilder buffer = new StringBuilder(2 * sessionIdLength + 20);
int resultLenBytes = 0;
while (resultLenBytes < sessionIdLength) {
getRandomBytes(random);
for (int j = 0;
j < random.length && resultLenBytes < sessionIdLength;
j++) {
byte b1 = (byte) ((random[j] & 0xf0) >> 4);
byte b2 = (byte) (random[j] & 0x0f);
if (b1 < 10)
buffer.append((char) ('0' + b1));
else
buffer.append((char) ('A' + (b1 - 10)));
if (b2 < 10)
buffer.append((char) ('0' + b2));
else
buffer.append((char) ('A' + (b2 - 10)));
resultLenBytes++;
}
}
return buffer.toString();
}
private static int getSessionIdLength() {
return sessionIdLength;
}
private static void getRandomBytes(byte bytes[]) {
SecureRandom random = randoms.poll();
if (random == null) {
random = createSecureRandom();
}
random.nextBytes(bytes);
randoms.add(random);
}
/**
* Create a new random number generator instance we should use for
* generating session identifiers.
*/
private static SecureRandom createSecureRandom() {
SecureRandom result = null;
long t1 = System.currentTimeMillis();
if (secureRandomClass != null) {
try {
// Construct and seed a new random number generator
Class<?> clazz = Class.forName(secureRandomClass);
result = (SecureRandom) clazz.newInstance();
} catch (Exception e) {
log.error(infoMap.get("sessionIdGeneratorBase.random"),
secureRandomClass, e);
}
}
if (result == null) {
// No secureRandomClass or creation failed. Use SecureRandom.
try {
if (secureRandomProvider != null &&
secureRandomProvider.length() > 0) {
result = SecureRandom.getInstance(secureRandomAlgorithm,
secureRandomProvider);
} else if (secureRandomAlgorithm != null &&
secureRandomAlgorithm.length() > 0) {
result = SecureRandom.getInstance(secureRandomAlgorithm);
}
} catch (NoSuchAlgorithmException e) {
log.error(infoMap.get("sessionIdGeneratorBase.randomAlgorithm"),
secureRandomAlgorithm, e);
} catch (NoSuchProviderException e) {
log.error(infoMap.get("sessionIdGeneratorBase.randomProvider"),
secureRandomProvider, e);
}
}
if (result == null) {
// Invalid provider / algorithm
try {
result = SecureRandom.getInstance("SHA1PRNG");
} catch (NoSuchAlgorithmException e) {
log.error(infoMap.get("sessionIdGeneratorBase.randomAlgorithm"),
secureRandomAlgorithm, e);
}
}
if (result == null) {
// Nothing works - use platform default
result = new SecureRandom();
}
// Force seeding to take place
result.nextInt();
long t2=System.currentTimeMillis();
if( (t2-t1) > 100 )
log.info(infoMap.get("sessionIdGeneratorBase.createRandom"),
result.getAlgorithm(), Long.valueOf(t2-t1));
return result;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment