以前单体应用控制登录session就够了,后来对于多客户端,可以用cas做统一认证,之前也成功配置过cas5.3.9实现多客户端单点登录单点登出案例,但是也很麻烦,最大的缺点是cas还要另起一个用来做统一认证的服务,占用一个端口,而且也很吃内存,相似原理的还可以用redis等缓存数据库弄一个共享缓存,也可以实现多客户端单点登录的功能,但是这两个的方法都要额外占用端口和服务,直到了解到JWT。
JWT是用java写的,可以生成一个独一无二的token字符串。
包括Header,Claim,ExpiresAt,sign,Header通常由两部分组成:令牌的类型,即JWT。和常用的散列算法,如HMAC SHA256或RSA。
例如:
{
"alg": "HS256",
"typ": "JWT"
}
Header部分的JSON被Base64Url编码,形成JWT的第一部分。
Clainm是要加密的StringId,ExpiresAt可以设置过期时间,sign可以自己私加密匙,如此:
JWT.create()
.withHeader(header)
.withClaim("userId", userId)
.withExpiresAt(date)
.sign(algorithm);
便可以创建出一个加密的token字符串,通过把这个字符串分发给其他客户端就可以识别是不是同一个用户,是哪个用户,从而很简单的实现单点登录。
maven下载jar包(截止发文最新版是3.10.2):
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.2</version>
</dependency>
创建JWTUtil工厂工具类
package com.zhaohy.app.utils;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
public class JWTUtil {//过期时间
private static final long EXPIRE_TIME = 15 * 60 * 1000;//默认15分钟
//私钥
private static final String TOKEN_SECRET = "privateKey";
/**
* 生成签名,15分钟过期
* @param **username**
* @param **password**
* @return
*/
public static String createToken(String userId) {
try {
// 设置过期时间
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
// 私钥和加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// 设置头部信息
Map<String, Object> header = new HashMap<>(2);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
.withClaim("userId", userId)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 生成token,自定义过期时间 毫秒
* @param **username**
* @param **password**
* @return
*/
public static String createToken(String userId,long expireDate) {
try {
// 设置过期时间
Date date = new Date(System.currentTimeMillis() + expireDate);
// 私钥和加密算法
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
// 设置头部信息
Map<String, Object> header = new HashMap<>(2);
header.put("Type", "Jwt");
header.put("alg", "HS256");
// 返回token字符串
return JWT.create()
.withHeader(header)
.withClaim("userId", userId)
.withExpiresAt(date)
.sign(algorithm);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 检验token是否正确
* @param **token**
* @return
*/
public static String verifyToken(String token){
try {
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
JWTVerifier verifier = JWT.require(algorithm).build();
DecodedJWT jwt = verifier.verify(token);
String userId = jwt.getClaim("userId").asString();
return userId;
} catch (Exception e){
return null;
}
}
public static void main(String[] args) {
String token = JWTUtil.createToken("zhaohy", 3000);
System.out.println("token == " + token);
String userId = JWTUtil.verifyToken(token);
System.out.println("userId == " + userId);
//新建定时任务
Runnable runnable = new Runnable() {
//run方法中是定时执行的操作
public void run() {
System.out.println(new Date());
String userId = JWTUtil.verifyToken(token);
System.out.println("userId == " + userId);
}
};
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
/*
* 参数一:command:执行线程
* 参数二:initialDelay:初始化延时
* 参数三:period:两次开始执行最小间隔时间
* 参数四:unit:计时单位
*/
service.scheduleAtFixedRate(runnable, 0, 4, TimeUnit.SECONDS);
}
}
运行里面的main方法:
通过截图中控制台打印出的效果表明,token可以被创建,也可以被解析,过期时间之后就不见了,过期时间是生效的,至此,就可以在项目中愉快的使用啦!