Closed supereagle closed 7 years ago
TokenGenerator.java
package com.auth.demo;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.Base64;
import java.util.Base64.Decoder;
import java.util.Base64.Encoder;
import java.util.Date;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
public class TokenGenerator {
private final long LIFETIME = 1000000; // The lifetime of token is 1000s.
// The secret key can be dynamically generated.
private final String SECRET_KEY = "Auth-d1mo";
private final Encoder ENCODER = Base64.getEncoder();
private final Decoder DECODER = Base64.getDecoder();
private final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
private final int SIG_LEN = 40; // The length of encoded token data.
// The generated token has 2 parts: token data encoded by Base64 + token
// data encoded by HmacSHA1 algorithm.
public String genToken(TokenArgs args) {
TokenData tokenData = getTokenDataFromTokenArgs(args);
String payload = JSON.toJSONString(tokenData);
try {
return ENCODER.encodeToString(payload.getBytes(StandardCharsets.UTF_8))
+ encodeHmacSHA(payload, SECRET_KEY);
} catch (SignatureException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
return null;
}
public boolean verifyToken(String token) {
String payload = new String(DECODER.decode(token.substring(0, token.length() - SIG_LEN)),
StandardCharsets.UTF_8);
String sig = token.substring(token.length() - SIG_LEN, token.length());
TokenData tokenData = JSON.parseObject(payload, TokenData.class);
if (tokenData != null) {
if (tokenData.getExpires() < new Date().getTime()) {
return false;
}
String expectedSig = null;
try {
expectedSig = encodeHmacSHA(payload, SECRET_KEY);
} catch (SignatureException e) {
e.printStackTrace();
return false;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return false;
} catch (InvalidKeyException e) {
e.printStackTrace();
return false;
}
if (!sig.equals(expectedSig)) {
return false;
}
return true;
}
return false;
}
private String encodeHmacSHA(String payload, String key)
throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
return new HexBinaryAdapter().marshal(mac.doFinal(payload.getBytes()));
}
private TokenData getTokenDataFromTokenArgs(TokenArgs args) {
// Verify the user info
if (args.getUsername() != "admin" || args.getPassword() != "admin") {
return null;
}
return new TokenData(args.getResource(), new Date().getTime() + LIFETIME);
}
}
TokenArgs.java
package com.auth.demo;
public class TokenArgs {
private String username;
private String password;
private String resource;
public TokenArgs(String username, String password, String resource) {
this.username = username;
this.password = password;
this.resource = resource;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
}
TokenData.java
package com.auth.demo;
import java.util.UUID;
public class TokenData {
private String resource;
private UUID salt; // Dynamical salt ensures every token is different.
private Long expires;
public TokenData(String resource, Long expires) {
this.resource = resource;
this.salt = UUID.randomUUID();
this.expires = expires;
}
public String getResource() {
return resource;
}
public void setResource(String resource) {
this.resource = resource;
}
public UUID getSalt() {
return salt;
}
public void setSalt(UUID salt) {
this.salt = salt;
}
public Long getExpires() {
return expires;
}
public void setExpires(Long expires) {
this.expires = expires;
}
}
References