package org.superboot.common.pub; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import org.superboot.base.BaseConstants; import org.superboot.base.BaseException; import org.superboot.base.BaseToken; import org.superboot.base.StatusCode; import org.superboot.entity.dto.UserMenuDTO; import org.superboot.entity.dto.UserResourceDTO; import org.superboot.utils.DateUtils; import javax.servlet.http.HttpServletRequest; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeUnit; /** * <b> 全局Redis工具类 </b> * <p> * 功能描述: 提供基于Redis的常用操作 * </p> */ @Component public class Pub_RedisUtils { @Autowired private RedisTemplate redisTemplate; @Autowired private Pub_Tools pubTools; /** * Token的状态,后期如果需要踢出用户则直接将此状态改为 Y */ public static final String TOKEN_STATUS = "TokenStatus"; /** * 锁定TOKEN */ public static final String TOKEN_STATUS_LOCKED = "Y"; /** * TOKEN未锁定 */ public static final String TOKEN_STATUS_UNLOCKED = "N"; /** * Token内存储的详细信息 */ public static final String TOKEN_ITEM = "TokenItem"; /** * TOKEN数据过期时间 默认15天如果15天内用户没有进行过登陆会销毁TOKEN缓存信息 */ public static final int TOKEN_EXPIRED_DAY = 15; /** * 用户权限信息 */ public static final String USER_RESOURCE = "UserResource"; /** * 用户菜单信息 */ public static final String USER_MENU = "UserMenu"; /** * 获取Redis操作实例 * * @return */ public RedisTemplate getRedisTemplate() { return redisTemplate; } /** * 存储第三方请求消息ID与Token对照关系 默认5分钟有效 * * @param messageId 消息ID * @param oToken 第三方授权TOKEN * @return */ public void setOtherMessId(String messageId, String oToken) { ValueOperations<String, String> operations = redisTemplate.opsForValue(); operations.set(messageId, oToken, 5, TimeUnit.MINUTES); } /** * 根据第三方TOKEN信息获取公司主键 * * @param messageId 第三方消息ID * @return */ public Long getPkGroupByOtherMessageId(String messageId) { if (StringUtils.isNotBlank(messageId)) { ValueOperations<String, String> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(messageId); if (exists) { String token = operations.get(messageId); return getPkGroupByOtherToken(token); } } return null; } /** * 设置第三方请求TOKEN与公司对照关系,默认有效期5分组 * * @param oToken TOKEN信息 * @param pkGroup 公司主键 */ public void setOtherToken(String oToken, Long pkGroup) { ValueOperations<String, Long> operations = redisTemplate.opsForValue(); operations.set(oToken, pkGroup, 5, TimeUnit.MINUTES); } /** * 根据第三方TOKEN信息获取公司主键 * * @param oToken 授权TOKEN * @return */ public Long getPkGroupByOtherToken(String oToken) { if (StringUtils.isNotBlank(oToken)) { ValueOperations<String, Long> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(oToken); if (exists) { return operations.get(oToken); } else { pubTools.checkOtherToken(oToken); return operations.get(oToken); } } return null; } /** * 设置会话的用户信息,默认保持时间为5分钟,如果后期涉及到长时间的操作,再调整超时时间 * * @param messageId 会话消息ID * @param token 用户信息 * @return */ public boolean setSessionInfo(String messageId, BaseToken token) { //构造信息 ValueOperations<String, String> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(messageId); if (exists) { return true; } else { operations.set(messageId, pubTools.objectToJson(token), 5, TimeUnit.MINUTES); return true; } } /** * 根据会话消息ID获取用户信息 * * @param messageId 会话消息ID * @return */ public BaseToken getSessionInfo(String messageId) { if (StringUtils.isNotBlank(messageId)) { ValueOperations<String, String> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(messageId); if (exists) { return pubTools.jsonToObject(operations.get(messageId), BaseToken.class); } } return null; } /** * 设置登陆用户信息 * * @param token 登陆TOKEN * @param baseToken 用户身份信息 * @return */ public BaseToken setTokenInfo(String token, BaseToken baseToken) { ValueOperations<String, HashMap> operations = redisTemplate.opsForValue(); //如果存在则先删除 boolean exists = redisTemplate.hasKey(token); if (exists) { //更新用户最后登陆信息 HashMap tokenItem = operations.get(token); tokenItem.put(TOKEN_ITEM, pubTools.objectToJson(baseToken)); operations.set(token, tokenItem, TOKEN_EXPIRED_DAY, TimeUnit.DAYS); } else { //将用户信息存储到Redis中 HashMap tokenItem = new HashMap(2); tokenItem.put(TOKEN_STATUS, TOKEN_STATUS_UNLOCKED); tokenItem.put(TOKEN_ITEM, pubTools.objectToJson(baseToken)); operations.set(token, tokenItem, TOKEN_EXPIRED_DAY, TimeUnit.DAYS); } return baseToken; } /** * 根据TOKEN获取用户信息,每次调用都会刷新有效期 * * @param token token * @return */ public BaseToken getTokenInfo(String token) { if (StringUtils.isNotBlank(token)) { ValueOperations<String, HashMap> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(token); if (exists) { //更新用户最后登陆信息 HashMap tokenItem = operations.get(token); //获取具体内容 BaseToken baseToken = null; if (tokenItem.get(Pub_RedisUtils.TOKEN_ITEM) instanceof BaseToken) { baseToken = (BaseToken) tokenItem.get(Pub_RedisUtils.TOKEN_ITEM); } else { baseToken = pubTools.jsonToObject(tokenItem.get(Pub_RedisUtils.TOKEN_ITEM) + "", BaseToken.class); } if (null != tokenItem) { //如果TOKEN已经锁定,则提示用户需要重新登陆 if (TOKEN_STATUS_LOCKED.equals(tokenItem.get(TOKEN_STATUS))) { baseToken.setErrCode(StatusCode.TOKEN_LOCKED); } else { baseToken.setLoginTime(DateUtils.getCurrentTime()); baseToken.setLoginDate(DateUtils.getCurrentDate()); tokenItem.put(TOKEN_ITEM, pubTools.objectToJson(baseToken)); //每次用户登陆都刷新TOKEN的有效期 operations.set(token, tokenItem, TOKEN_EXPIRED_DAY, TimeUnit.DAYS); } return baseToken; } } } return null; } /** * 设置TOKEN白名单,KEY 为 * * @param pkUser 用户主键 * @param platform 来源平台 * @param version 来源版本 * @param token TOKEN信息 */ public void setTokenAllow(long pkUser, String platform, String version, String token) { ValueOperations<String, HashMap> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(BaseConstants.USER_TOKEN + "-" + pkUser); if (exists) { HashMap<String, Object> tokenMap = operations.get(BaseConstants.USER_TOKEN + "-" + pkUser); //添加新的TOKEN信息到缓存中 if (!tokenMap.containsKey(token)) { //TOKEN详细信息 HashMap<String, String> itemMap = new HashMap(2); itemMap.put(BaseConstants.TOKEN_VERSION, version); itemMap.put(BaseConstants.TOKEN_PLATFORM, platform); tokenMap.put(token, itemMap); } //添加新的版本与平台信息到缓存中 if (!tokenMap.containsKey(platform + "-" + version)) { tokenMap.put(platform + "-" + version, token); } //清理历史 redisTemplate.delete(BaseConstants.USER_TOKEN + "-" + pkUser); //重新设置以便刷新最后失效时间 operations.set(BaseConstants.USER_TOKEN + "-" + pkUser, tokenMap, TOKEN_EXPIRED_DAY, TimeUnit.DAYS); } else { //TOKEN详细信息 HashMap<String, String> itemMap = new HashMap(2); itemMap.put(BaseConstants.TOKEN_VERSION, version); itemMap.put(BaseConstants.TOKEN_PLATFORM, platform); HashMap<String, Object> tokenMap = new HashMap<>(1); tokenMap.put(token, itemMap); tokenMap.put(platform + "-" + version, token); //重新设置以便刷新最后失效时间 operations.set(BaseConstants.USER_TOKEN + "-" + pkUser, tokenMap, TOKEN_EXPIRED_DAY, TimeUnit.DAYS); } } /** * 根据来源平台与版本获取TOKEN * * @param pkUser 用户主键 * @param platform 来源平台 * @param version 来源版本 * @return */ public String getTokenAllow(long pkUser, String platform, String version) { ValueOperations<String, HashMap> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(BaseConstants.USER_TOKEN + "-" + pkUser); if (exists) { HashMap<String, Object> tokenMap = operations.get(BaseConstants.USER_TOKEN + "-" + pkUser); //循环处理TOKEN白名单里失效的TOKEN for (String key : tokenMap.keySet()) { //判断对象是TOKEN if (key.startsWith("Bearer")) { //如果TOKEN已经不存在了 if (!redisTemplate.hasKey(key)) { //清理失效TOKEN信息 cleanTokenAllow(pkUser, key); } } } if (tokenMap.containsKey(platform + "-" + version)) { return "" + tokenMap.get(platform + "-" + version); } } return null; } /** * 根据TOKEN获取来源平台与版本 * * @param pkUser 用户主键 * @param token TOKEN * @return */ public HashMap<String, String> getTokenAllowItem(long pkUser, String token) { ValueOperations<String, HashMap> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(BaseConstants.USER_TOKEN + "-" + pkUser); if (exists) { HashMap<String, Object> tokenMap = operations.get(BaseConstants.USER_TOKEN + "-" + pkUser); if (tokenMap.containsKey(token)) { return (HashMap<String, String>) tokenMap.get(token); } } return null; } /** * 清理全部TOKEN信息(多用于修改密码后) * * @param pkUser 用户主键 */ public void cleanAllToken(long pkUser) { //清理白名单与TOKEN信息 ValueOperations<String, HashMap> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(BaseConstants.USER_TOKEN + "-" + pkUser); if (exists) { HashMap<String, Object> tokenMap = operations.get(BaseConstants.USER_TOKEN + "-" + pkUser); //循环处理TOKEN白名单里失效的TOKEN for (String key : tokenMap.keySet()) { //判断对象是TOKEN if (key.startsWith("Bearer")) { redisTemplate.delete(key); } } redisTemplate.delete(BaseConstants.USER_TOKEN + "-" + pkUser); } } /** * 根据来源平台+版本清理TOKEN白名单 * * @param pkUser 用户主键 * @param platform 来源平台 * @param version 来源版本 */ public void cleanTokenAllow(long pkUser, String platform, String version) { ValueOperations<String, HashMap> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(BaseConstants.USER_TOKEN + "-" + pkUser); if (exists) { HashMap<String, Object> tokenMap = operations.get(BaseConstants.USER_TOKEN + "-" + pkUser); String token = "" + tokenMap.get(platform + "-" + version); tokenMap.remove(token); tokenMap.remove(platform + "-" + version); //重新设置以便刷新最后失效时间 operations.set(BaseConstants.USER_TOKEN + "-" + pkUser, tokenMap, TOKEN_EXPIRED_DAY, TimeUnit.DAYS); } } /** * 根据token清理TOKEN白名单 * * @param pkUser 用户主键 * @param token TOKEN信息 */ public void cleanTokenAllow(long pkUser, String token) { ValueOperations<String, HashMap> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(BaseConstants.USER_TOKEN + "-" + pkUser); if (exists) { HashMap<String, Object> tokenMap = operations.get(BaseConstants.USER_TOKEN + "-" + pkUser); HashMap<String, String> itemMap = (HashMap<String, String>) tokenMap.get(token); tokenMap.remove(token); //判断TOKEN的信息与平台版本存储的一致才进行删除,理论上会一致,但是不排除出现同平台的信息不一致的情况 String tokenStr = "" + tokenMap.get(itemMap.get(BaseConstants.TOKEN_PLATFORM) + "-" + itemMap.get(BaseConstants.TOKEN_VERSION)); if (token.equals(tokenStr)) { tokenMap.remove(itemMap.get(BaseConstants.TOKEN_PLATFORM) + "-" + itemMap.get(BaseConstants.TOKEN_VERSION)); } //重新设置以便刷新最后失效时间 operations.set(BaseConstants.USER_TOKEN + "-" + pkUser, tokenMap, TOKEN_EXPIRED_DAY, TimeUnit.DAYS); } } /** * 设置Token的锁定状态 * * @param token 用户Token */ public void tokenLocked(String token, boolean locked) { ValueOperations<String, HashMap> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(token); if (exists) { HashMap tokenItem = operations.get(token); if (locked) { tokenItem.put(TOKEN_STATUS, TOKEN_STATUS_LOCKED); } else { tokenItem.put(TOKEN_STATUS, TOKEN_STATUS_UNLOCKED); } operations.set(token, tokenItem, TOKEN_EXPIRED_DAY, TimeUnit.DAYS); } } /** * 设置用户权限信息 * * @param userId 用户ID * @param resourceHashMap 用户权限信息MAP KEY为模块ID+类名+方法名 * @return */ public void setUserResource(long userId, HashMap<String, UserResourceDTO> resourceHashMap) { ValueOperations<String, String> operations = redisTemplate.opsForValue(); if (redisTemplate.hasKey(USER_RESOURCE + userId)) { redisTemplate.delete(USER_RESOURCE + userId); } operations.set(USER_RESOURCE + userId, pubTools.objectToJson(resourceHashMap)); } /** * 获取用户权限信息 * * @param userId 用户ID * @return */ public JSONObject getUserResource(long userId) { ValueOperations<String, String> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(USER_RESOURCE + userId); if (exists) { return pubTools.jsonToObject(operations.get(USER_RESOURCE + userId), JSONObject.class); } return null; } /** * 设置用户菜单 * * @param userId 用户主键 * @param menuList 用户菜单列表 */ public void setUserMenu(long userId, List<UserMenuDTO> menuList) { ValueOperations<String, String> operations = redisTemplate.opsForValue(); if (redisTemplate.hasKey(USER_MENU + userId)) { redisTemplate.delete(USER_MENU + userId); } if (null == menuList) { redisTemplate.delete(USER_MENU + userId); } else { operations.set(USER_MENU + userId, pubTools.objectToJson(menuList)); } } /** * 获取用户菜单 * * @param userId 用户ID * @return */ public List getUserMenu(long userId) { ValueOperations<String, String> operations = redisTemplate.opsForValue(); boolean exists = redisTemplate.hasKey(USER_MENU + userId); if (exists) { Object list = operations.get(USER_MENU + userId); if (list instanceof List) { return (List<UserMenuDTO>) list; } Object o = JSON.parse(operations.get(USER_MENU + userId)); List<UserMenuDTO> rList = new ArrayList<>(); List data = JSON.toJavaObject((JSON) o, List.class); for (int i = 0; i < data.size(); i++) { UserMenuDTO item = ((JSONObject) data.get(i)).toJavaObject(UserMenuDTO.class); rList.add(item); } return rList; } return null; } /** * 通过请求信息获取用户TOKEN信息 * * @param request 请求信息 * @return */ public BaseToken getTokenByRequest(HttpServletRequest request) { BaseToken baseToken = null; //获取用户TOKEN信息,默认情况均通过消息ID获取 String token = request.getHeader(BaseConstants.GLOBAL_KEY.toLowerCase()); if (StringUtils.isBlank(token)) { //消息ID未获取到的时候,多数是内部测试阶段,此时使用Token进行获取 token = request.getHeader(BaseConstants.TOKEN_KEY); if (StringUtils.isBlank(token)) { throw new BaseException(StatusCode.TOKEN_INVALID); } else { baseToken = getTokenInfo(token); } } else { baseToken = getSessionInfo(token); } if (null == baseToken) { throw new BaseException(StatusCode.TOKEN_LOCKED); } //判断获取TOKEN,TOKEN本身存在问题,比如已经封存 if (null != baseToken.getErrCode()) { throw new BaseException(baseToken.getErrCode()); } return baseToken; } /** * 通过请求信息获取用户第三方授权公司 * * @param request 请求信息 * @return */ public Long getPkGroupByRequest(HttpServletRequest request) { //获取第三方公司信息,默认情况均通过消息ID获取 String token = request.getHeader(BaseConstants.OTHER_MESSAGE_ID.toLowerCase()); if (StringUtils.isBlank(token)) { //消息ID未获取到的时候,多数是内部测试阶段,此时使用Token进行获取 token = request.getHeader(BaseConstants.OTHER_TOKEN_KEY); if (StringUtils.isBlank(token)) { token = request.getHeader(BaseConstants.GLOBAL_KEY.toLowerCase()); if (StringUtils.isBlank(token)) { token = request.getHeader(BaseConstants.TOKEN_KEY); if (StringUtils.isNotBlank(token)) { return getTokenInfo(token).getPkGroup(); } } else { return getSessionInfo(token).getPkGroup(); } } else { return getPkGroupByOtherToken(token); } } else { return getPkGroupByOtherMessageId(token); } //返回一个不存在的ID return -99L; } }