jwt(json web token)是一种能够允许我们在用户和服务器之间传递安全可靠信息的规范。它可以采用对称加密和非对称加密的方式,对我们所要传递的数据进行加密,防止数据的泄露。在web应用中,jwt通常可以结合Spring-security,对访问的页面进行安全保护,如果有需要,可以参照本文参考文献中的内容。本文主要对jwt的类进行封装,生成tocken信息。
JWT 由三部分组成 头部(header)、荷载(payload) 、签名(signature)
在使用Jwt时,我们首先在pom中引用jwt的lib
然后,我们编写一个产生tocken 和获取tocken 的java通用类,也就是对jwt中的方法进行简单的封装<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.0</version> </dependency>
public class JWT { /** * 利用jwt生成token信息. * @param claims 数据声明(Claim)其实就是一个Map,比如我们想放入用户名, * 可以简单的创建一个Map然后put进去 * @param secret 用于进行签名的秘钥 * @return * @throws Exception */ public static String generateToken(Map<String, Object> claims,String secret) throws Exception { DESCoder desCoder = new DESCoder(); Key key = desCoder.toKey(secret); //设置过期时间为10分钟 Date ecpiration = new Date(System.currentTimeMillis()+600000L); return Jwts.builder() .setClaims(claims) .setExpiration(ecpiration) .signWith(SignatureAlgorithm.HS512, key) //采用什么算法是可以自己选择的,不一定非要采用HS512 .compact(); } /** * 利用jwt解析token信息. * @param token 要解析的token信息 * @param secret 用于进行签名的秘钥 * @return * @throws Exception */ public static Optional<Claims> getClaimsFromToken(String token,String secret) throws Exception { Claims claims; DESCoder desCoder = new DESCoder(); Key key = desCoder.toKey(secret); try { claims = Jwts.parser() .setSigningKey(key) .parseClaimsJws(token) .getBody(); return Optional.of(claims); } catch (Exception e) { return Optional.empty(); } } /** * 验证token是否过期 * @param tooken 要解析的token信息 * @param secret 用于进行签名的秘钥 * @return * @throws Exception */ public static boolean isExpired(String tooken,String secret) throws Exception{ Optional<Claims> claims= getClaimsFromToken(tooken,secret); if(claims.isPresent()){ Date expiration = claims.get().getExpiration(); return expiration.before(expiration); } return false; } /** * 获取tooken中的参数值 * @param tooken 要解析的token信息 * @param secret 用于进行签名的秘钥 * @return * @throws Exception */ public static Map<String,Object> extractInfo(String token,String secret) throws Exception{ Optional<Claims> claims = getClaimsFromToken(token,secret); if(claims.isPresent()){ Map<String,Object> info = new HashMap<String,Object>(); Set<String> keySet = claims.get().keySet(); //通过迭代,提取token中的参数信息 Iterator<String> iterator = keySet.iterator(); while(iterator.hasNext()){ String key = iterator.next(); Object value = claims.get().get(key); info.put(key,value); } return info; } return null; } }
上述方法中的generateToken(Map<String, Object> claims,String secret)为产生token的方法,claims中为包含发送内容的map数据,方法中的SignatureAlgorithm.HS512 为加密算法,为对称加密,如果想使用非对称加密方法,需要改为RS256,同时,传入的key必须是公私钥,具体可参照“RS256加密JWT生成、验证”。signWith(SignatureAlgorithm.HS512, key)方法中的“key”可以为String类型,也可以为Key类型,如果我们在方法中传入keyd的类型为String时,signWith会自动将其转化为Key类型。上面方法中,我们直接传入String类型的secret为使用base64编码DES加密的String,大家如果觉得麻烦,可以直接输入String生成token,以及使用相同的string解密token信息,不需要看以下内容。
上面中我们使用到的DESCoder类的内容为:
private Key toKey(byte[] key) throws Exception { DESKeySpec dks = new DESKeySpec(key); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORTHM); SecretKey secretKey = keyFactory.generateSecret(dks); return secretKey; } /** * * @param key key(Base64编码) * @return * @throws Exception */ public Key toKey(String key) throws Exception{ byte[] keyBytes = (new BASE64Decoder()).decodeBuffer(key); Key keyObj = toKey(keyBytes); return keyObj; }
DES加密算法的生成方法为
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.security.Key; import java.security.SecureRandom; import java.util.Map; import javax.crypto.KeyGenerator; import sun.misc.BASE64Encoder; public class DESBuilder { /** 加密算法 */ public static final String KEY_ALGORTHM = "DES"; private Key key; /** * 构造函数. * * @param str * 传入的字符串,根据字符串随机生成Key */ public DESBuilder(String str) { generatorRandomKey(str); } /** * @param strKey * 通过strKey生成随机Key */ public void generatorRandomKey(String strKey) { try { KeyGenerator generator = KeyGenerator.getInstance(KEY_ALGORTHM); generator.init(new SecureRandom(strKey.getBytes())); this.key = generator.generateKey(); generator = null; } catch (Exception e) { throw new RuntimeException("Error initializing SqlMap class. Cause: " + e); } } /** * @param strKey * 通过strKey生成Key * * @return Key对象 */ public Key getKey() { return key; } /** * @param strKey * 通过strKey生成Key * * @return Key对象 */ public String getKeyToString() { return (new BASE64Encoder()).encodeBuffer(key.getEncoded()); } /** * @param filePath * 秘钥的存储路径(建议秘钥使用“.bat”后缀) * * @return 文件 */ public void getKeyToFile(String keyAddress) { FileOutputStream fileOutput = null; ObjectOutputStream objectOutput = null; try { fileOutput = new FileOutputStream(keyAddress); objectOutput = new ObjectOutputStream(fileOutput); objectOutput.writeObject(this.key); System.out.println("success: " + keyAddress); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { fileOutput.close(); objectOutput.close(); } catch (IOException e) { e.printStackTrace(); } } } }至此,已经介绍完成jwt生成和解析token信息的方法,里面涉及到如何进行base64编码解码,如何生成用DES加解密以及Key类型数据的产生。
参考文献
1、JSON Web Token - 在Web应用间安全地传递信息
3、使用JWT保护你的Spring Boot应用 - Spring Security实战
4、使用JWT和Spring Security保护REST API