0
点赞
收藏
分享

微信扫一扫

jwt token进行登录挤掉上次登录

624c95384278 2022-01-26 阅读 75
java

使用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("退出登录");
	}

实现代码大致就这些

举报

相关推荐

0 条评论