使用jwt中的token来挤掉前一个用户
一.我的大概思路:
1.首先创建一个服务器全局static变量的map集合。
2.在登陆的时候,做如下操作:
a) map集合是不容许相同键的,遍历map集合的token,解析token中的用户名是否是当前登陆的用户名,如果存在,将当前的token的值设置成false并移除当前的token。
b) 然后把键:新的token值,和键值:true存到map集合中。
3.在每次请求数据的过滤器中,做如下操作:
a)拿到token,根据键token,拿到键值bool值,如果token不存在map中就提示重新登录。
3.在注销的时候,删除map集合中的token。
4.提高遍历效率.
使用定时任务定期清理map集合中已经过期的token。我的实现是每次有新用户登录的时候,顺路将map集合中的令牌已经过期的token删除。
二.实现代码.
1.首先创建一个服务器全局static变量的map集合。
package www.wensi.com.vmi.commom;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.util.ObjectUtils;
import www.wensi.com.vmi.service.Utils.JwtUtil;
public class TokenCacheUtil {
private static Map<Object, Object> cacheMap = new HashMap<Object, Object>();
/**
* 单实例构造方法
*/
private TokenCacheUtil() {
super();
}
/**
* 根据键获取时间long
*
* @param key
* @return
*/
public static Long getServerStartdt(String key) {
return (Long) cacheMap.get(key);
}
/**
* 设置布尔值的缓存
*
* @param key
* @param date
* @return
*/
public synchronized static Map<Object, Object> setSimpleFlag(String key, Long date) {
cacheMap.put(key, date);
return cacheMap;
}
/**
* 判断是否存在一个缓存
*
* @param key
* @return
*/
public synchronized static boolean hasCache(String key) {
return cacheMap.containsKey(key);
}
/**
* 判断是否存在缓存
*
* @param key
* @return
*/
public synchronized static boolean hasOneCache(String key) {
return !ObjectUtils.isEmpty(cacheMap);
}
/**
* 清除所有缓存
*/
public synchronized static void clearAll() {
cacheMap.clear();
}
/**
* 清除指定的缓存
*
* @param key
*/
public synchronized static void clearOnly(String key) {
cacheMap.remove(key);
}
/**
* 获取缓存中的大小
*
* @return
*/
public static int getCacheSize() {
return cacheMap.size();
}
/**
* 根据最新的token通过用户名相同删除之前的token
*
* @param token
*/
public static void existByUserName(String token, Long expire) {
String nowUserName = JwtUtil.getUserName(token);
Iterator<Entry<Object, Object>> it = cacheMap.entrySet().iterator();
while (it.hasNext()) {
Entry<Object, Object> entry = it.next();
String key = entry.getKey().toString();
String value = entry.getValue().toString();
if (nowUserName.equalsIgnoreCase(JwtUtil.getUserName(key))) {
it.remove();
}
// 顺路可以把过期的也移除下
if ((new Date()).getTime() - (Long.parseLong(value)) >= expire) {
it.remove();
}
}
}
/**
* 过滤当前时间如果过期了就移除
*
* @param time
*/
public static void deleteTokenForExpired(Long time) {
// TODO Auto-generated method stub
Iterator<Entry<Object, Object>> it = cacheMap.entrySet().iterator();
while (it.hasNext()) {
Entry<Object, Object> entry = it.next();
String value = entry.getValue().toString();
// 顺路可以把过期的也移除下
if ((new Date()).getTime() - (Long.parseLong(value)) >= time) {
it.remove();
}
}
}
}
2.在登录的时候:
a)根据最新的token通过用户名相同删除之前的token,并把过期的token删除
b) 把新的token放到缓存的数据之中。
/**
* 登录认证并创建token
*
* @param userName
* 用户名
* @param password
* 密码
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public BaseResponse authAndCreateTokenNew(String userName, String password) {
SysUser user = null;
try {
user = userService.authUser(userName, password);
if (user == null) {
log.error("用户:{},系统出错登录失败", userName);
return new BaseResponse(StatusCode.FAIL.getStatus(), "系统出错登录失败");
}
} catch (Exception e) {
BaseResponse response = new BaseResponse(StatusCode.FAIL.getStatus(), e.getMessage());
return response;
}
if (user.getRoleId() == null) {// 用户登录
user.setRoleId(0);
}
// 创建token
String accessToken = JwtUtil.createJWT(user.getUserId().toString(), userName, Constant.ACCESS_TOKEN_EXPIRE,
user.getRoleId().toString());
LoginModel loginModel = new LoginModel();
loginModel.setToken(accessToken);
loginModel.setAccessExpire(Constant.ACCESS_TOKEN_EXPIRE);
loginModel.setIsDefaultPassword(user.getIsDefaultPassword());
// 根据最新的token通过用户名相同删除之前的token
TokenCacheUtil.existByUserName(loginModel.getToken(), loginModel.getAccessExpire());
// 将token放到缓存的数据之中
TokenCacheUtil.setSimpleFlag(loginModel.getToken(), new Date().getTime());
return new BaseResponse(StatusCode.SUCCESS, loginModel);
}
3.在每次请求数据的过滤器中:
a)判断是否存在有缓存,如果不存在缓存,说明系统可能刚升级,则原来的token提示“登录信息已过期,请重新登录”
b) 判断是否存在该缓存,如果不存在该token缓存,则提示“您的账号在另一处地点登录,您已被迫下线”
if (!TokenCacheUtil.hasOneCache(accessToken)) {
// 登录信息已过期,请重新登录
BaseResponse baseResponse = new BaseResponse(StatusCode.TOKEN_EXPIRATION);
log.debug("用户验证失败,url:{},token:{}", request.getRequestURL(),
StatusCode.TOKEN_EXPIRATION.getMessage());
commonService.print(response, baseResponse);
return false;
} else if (!TokenCacheUtil.hasCache(accessToken)) {
// 您的账号在另一处地点登录,您已被迫下线
BaseResponse baseResponse = new BaseResponse(StatusCode.TOKEN_ALREADY_OTHER_PALCE_LOGIN);
log.debug("用户验证失败,url:{},token:{}", request.getRequestURL(),
StatusCode.TOKEN_ALREADY_OTHER_PALCE_LOGIN.getMessage());
commonService.print(response, baseResponse);
return false;
}
4.注销登录
a)清除指定的缓存
/**
* 退出注销登录~前端需要清除token并重新进行登录
*
* @param token
* @return
*/
@SuppressWarnings("rawtypes")
@RequestMapping(value = "/u/user/logout", method = RequestMethod.GET)
public BaseResponse logout(@RequestHeader String token) {
log.info("退出登录:token{},userId:{}", token);
if (StringUtils.isBlank(token)) {
return new BaseResponse(StatusCode.INVALID_PARAMS);
}
// 清除指定的缓存
TokenCacheUtil.clearOnly(token);
return ResultUtil.success("退出登录");
}
实现代码大致就这些