package study; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.security.KeyFactory; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; public class RsaUtils { private static final int DEFAULT_KEY_SIZE = 2048; /** * 从文件中读取公钥 * * @param filename 公钥保存路径,相对于classpath * @return 公钥对象 * @throws Exception */ public static PublicKey getPublicKey(String filename) throws Exception { byte[] bytes = readFile(filename); return getPublicKey(bytes); } /** * 从文件中读取密钥 * * @param filename 私钥保存路径,相对于classpath * @return 私钥对象 * @throws Exception */ public static PrivateKey getPrivateKey(String filename) throws Exception { byte[] bytes = readFile(filename); return getPrivateKey(bytes); } /** * 获取公钥 * * @param bytes 公钥的字节形式 * @return * @throws Exception */ private static PublicKey getPublicKey(byte[] bytes) throws Exception { bytes = Base64.getDecoder().decode(bytes); X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance("RSA"); return factory.generatePublic(spec); } /** * 获取密钥 * * @param bytes 私钥的字节形式 * @return * @throws Exception */ private static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException { bytes = Base64.getDecoder().decode(bytes); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes); KeyFactory factory = KeyFactory.getInstance("RSA"); return factory.generatePrivate(spec); } /** * 根据密文,生存rsa公钥和私钥,并写入指定文件 * * @param publicKeyFilename 公钥文件路径 * @param privateKeyFilename 私钥文件路径 * @param secret 生成密钥的密文 */ public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret, int keySize) throws Exception { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); SecureRandom secureRandom = new SecureRandom(secret.getBytes()); keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom); KeyPair keyPair = keyPairGenerator.genKeyPair(); // 获取公钥并写出 byte[] publicKeyBytes = keyPair.getPublic().getEncoded(); publicKeyBytes = Base64.getEncoder().encode(publicKeyBytes); writeFile(publicKeyFilename, publicKeyBytes); // 获取私钥并写出 byte[] privateKeyBytes = keyPair.getPrivate().getEncoded(); privateKeyBytes = Base64.getEncoder().encode(privateKeyBytes); writeFile(privateKeyFilename, privateKeyBytes); } private static byte[] readFile(String fileName) throws Exception { return Files.readAllBytes(new File(fileName).toPath()); } private static void writeFile(String destPath, byte[] bytes) throws IOException { File dest = new File(destPath); if (!dest.exists()) { dest.createNewFile(); } Files.write(dest.toPath(), bytes); } }
package study; import java.util.Date; import java.util.HashMap; import java.util.Map; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; /** * @author Administrator 简单的字符串生成 */ public abstract class JWTUtils { public static final String UID = "uid"; private static final String SECRET = "aflkdsfkliewqfhksa"; private static final long EXPIRE = 1 * 1000; private static final String pubKey = "D:\11.pub"; private static final String priKey = "D:\11.se"; /** * 生成token * * @param uid * @return */ public static String generate(Integer uid) { Date nowDate = new Date(); // 过期时间 Date expireDate = new Date(nowDate.getTime() + EXPIRE * 1000); Map<String, Object> claims = new HashMap<>(1); claims.put(UID, uid); return Jwts.builder().setClaims(claims).setIssuedAt(nowDate).setExpiration(expireDate) .signWith(SignatureAlgorithm.HS512, SECRET).compact(); } /** * 解析Claims * * @param token * @return */ public static Claims getClaim(String token) { Claims claims = null; try { claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody(); } catch (Exception e) { return null; } return claims; } /** * 获取jwt发布时间 */ public static Date getIssuedAt(String token) { return getClaim(token).getIssuedAt(); } /** * 获取UID */ public static Integer getUid(String token) { return Integer.valueOf(getClaim(token).get(UID).toString()); } /** * 获取jwt失效时间 */ public static Date getExpiration(String token) { return getClaim(token).getExpiration(); } /** * 验证token是否失效 * * @param token * @return true:过期 false:没过期 */ public static boolean isExpired(String token) { try { final Date expiration = getExpiration(token); return expiration.before(new Date()); } catch (ExpiredJwtException expiredJwtException) { return true; } } }
package study; import java.util.Date; import java.util.HashMap; import java.util.Map; import io.jsonwebtoken.Claims; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; /** * @author Administrator rsa方式生成token */ public abstract class JWTRsaUtils { public static final String UID = "uid"; private static final long EXPIRE = 1 * 1000; private static final String pubKey = "D:\11.pub"; private static final String priKey = "D:\11.se"; public static String generate(Integer uid) throws Exception { Date nowDate = new Date(); // 过期时间 Date expireDate = new Date(nowDate.getTime() + EXPIRE * 1000); Map<String, Object> claims = new HashMap<>(1); claims.put(UID, uid); return Jwts.builder().setClaims(claims).setIssuedAt(nowDate).setExpiration(expireDate) .signWith(SignatureAlgorithm.RS256, RsaUtils.getPrivateKey(priKey)).compact(); } public static Claims getClaim(String token) { Claims claims = null; try { claims = Jwts.parser().setSigningKey(RsaUtils.getPublicKey(pubKey)).parseClaimsJws(token).getBody(); } catch (Exception e) { return null; } return claims; } /** * 获取jwt发布时间 */ public static Date getIssuedAt(String token) { return getClaim(token).getIssuedAt(); } /** * 获取UID */ public static Integer getUid(String token) { return Integer.valueOf(getClaim(token).get(UID).toString()); } /** * 获取jwt失效时间 */ public static Date getExpiration(String token) { return getClaim(token).getExpiration(); } /** * 验证token是否失效 * * @param token * @return true:过期 false:没过期 */ public static boolean isExpired(String token) { try { final Date expiration = getExpiration(token); return expiration.before(new Date()); } catch (ExpiredJwtException expiredJwtException) { return true; } } }
// JWT测试 // String token = JWTUtils.generate(123); // System.out.println(token); // Thread.sleep(2 * 1000); // System.out.println(JWTUtils.isExpired(token)); // Integer uid = JWTUtils.getUid(token); // System.out.println(uid); // RsaUtils.generateKey("D:\11.pub", "D:\11.se", "122", 1024); String token = JWTRsaUtils.generate(123); System.out.println(token); System.out.println(JWTRsaUtils.getClaim(token));
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency> <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>3.4.0</version> </dependency>
token失效处理方式:
用户表维护一个登录时间字段lastLoginDate,每次登录,退出,修改密码都更新此字段,
然后jwt生成时有个签发时间,根据签发时间比对登录时间,
如果签发时间在登录时间前则视其为失效. 我的项目中用的jjwt(0.7.0版本),下面是代码示例
当然也可以用redis缓存,登录刷新即可