-
-
Save exceptionplayer/e0643078b852348c62da7b2bd9778cf6 to your computer and use it in GitHub Desktop.
tomcat中生成JSESSIONID的代码
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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