http是个无差别访问,就是无论你访问多少次,服务器都无法知道你是谁。所以后来有了session出现来解决用户验证的问题,但是session是个很重要的资源,往往保存少量且重要的数据。但是随着用户量增大,session所占的内存也越来越大,服务器的压力也大,所有后面出现了token,它把session的数据加密,可以保存进redis或者本地数据库,需要用户验证的时候再拿出来解析,还可以设置超时时间,某种程度上可以取代session的验证或者与之结合来验证用户,而且最重要的是token持久化很方便,加密后的token字符串你可以随意保存,并且token的加密可自定义,也不怕别人截获token解析出用户数据。现在已经接触了不少项目在用户信息中添加了token字段,来保存加密后的token数据。
完整的token工具类(含数据转化和加密方法):JavaWebToken.java
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;
import java.util.Map;
public class JavaWebToken {
private static Logger log = LoggerFactory.getLogger(JavaWebToken.class);
//该方法使用HS256算法和Secret:bankgl生成signKey
private static Key getKeyInstance() {
//We will sign our JavaWebToken with our ApiKey secret
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("abcdefghijkl");//加密,里面的字符串可自行定义
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
return signingKey;
}
/**使用HS256签名算法和生成的signingKey最终的Token,claims中是有效载荷
* @param claims 待转化的数据
* @return token字符串
*/
public static String createJavaWebToken(Map<String, Object> claims) {
long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);
return Jwts.builder()
.setClaims(claims)
.setExpiration(new Date(nowMillis + 1000*60*60*24*7))//超时时间,设置为7天
.setIssuedAt(now)
.setNotBefore(now)
.signWith(SignatureAlgorithm.HS256, getKeyInstance())
.compact();
}
/**解析Token,同时也能验证Token,当验证失败返回null
* @param jwt token字符串
* @return 解析的数据
*/
public static Map<String, Object> parserJavaWebToken(String jwt) {
try {
Map<String, Object> jwtClaims =
Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwt).getBody();
return jwtClaims;
} catch (Exception e) {
log.error("json web token verify failed : " + e.getMessage());
return null;
}
}
}
测试方法:
public static void main(String[] args) throws UnsupportedEncodingException {
Map<String, Object> claims = new HashMap<String,Object>();
//模拟添加session中的用户数据
claims.put("id", "555");
claims.put("name", "小白");
claims.put("pass", "555");
//转成token
String myToken = JavaWebToken.createJavaWebToken(claims);
System.out.println("我的token数据:" + myToken);
//token转化为原数据
Map<String, Object> myTokenMap = JavaWebToken.parserJavaWebToken(myToken);
System.out.println("token转化为Map:" + myTokenMap);
}
结果:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/E:/maven/jar/org/slf4j/slf4j-simple/1.7.21/slf4j-simple-1.7.21.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/E:/maven/jar/org/slf4j/slf4j-log4j12/1.7.7/slf4j-log4j12-1.7.7.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
我的token数据:eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE1NTczODM1MTIsInBhc3MiOiI1NTUiLCJuYW1lIjoi5bCP55m9IiwiaWQiOiI1NTUiLCJleHAiOjE1NTc5ODgzMTIsImlhdCI6MTU1NzM4MzUxMn0.2osIe0ULpaLtivMa_PNN_8lK5rLT6MWriMV6au5zfJc
token转化为Map:{nbf=1557383512, pass=555, name=小白, id=555, exp=1557988312, iat=1557383512}