package jnpf.util; import cn.dev33.satoken.same.SaSameUtil; import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.session.SaTerminalInfo; import cn.dev33.satoken.stp.StpUtil; import cn.dev33.satoken.stp.parameter.SaLoginParameter; import cn.hutool.core.text.StrPool; import jnpf.base.UserInfo; import jnpf.consts.DeviceType; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import java.util.List; import java.util.stream.Collectors; import static jnpf.consts.AuthConsts.TOKEN_PREFIX_SP; /** * @author JNPF开发平台组 * @version V3.1.0 * @copyright 引迈信息技术有限公司 * @date 2021/3/16 10:57 */ @Slf4j @Component public class UserProvider { private static RedisUtil redisUtil; private static CacheKeyUtil cacheKeyUtil; public static final String USER_INFO_KEY = "userInfo"; private static final ThreadLocal USER_CACHE = new ThreadLocal<>(); public UserProvider(RedisUtil redisUtil, CacheKeyUtil cacheKeyUtil) { UserProvider.redisUtil = redisUtil; UserProvider.cacheKeyUtil = cacheKeyUtil; } // =================== 登录相关操作 =================== /** * 登录系统 适用于Request环境 * * @param userInfo 登录用户信息 */ public static void login(UserInfo userInfo) { setLocalLoginUser(userInfo); StpUtil.login(splicingLoginId(userInfo.getUserId())); userInfo.setToken(StpUtil.getTokenValueNotCut()); userInfo.setSecurityKey(DesUtil.aesOrDecode(TicketUtil.createTicket(userInfo.getToken(), 10*24*60*60000L), true, true)); setLoginUser(userInfo); } /** * 登录系统 适用于Request环境 * * @param userInfo 用户信息 * @param loginModel 登录参数 */ public static void login(UserInfo userInfo, SaLoginParameter loginModel) { setLocalLoginUser(userInfo); StpUtil.login(splicingLoginId(userInfo.getUserId()), loginModel); userInfo.setToken(StpUtil.getTokenValueNotCut()); userInfo.setSecurityKey(DesUtil.aesOrDecode(TicketUtil.createTicket(userInfo.getToken(), 10*24*60*60000L), true, true)); setLoginUser(userInfo); } /** * 适用于非Request环境 * @param userInfo * @param loginModel */ public static void loginNoRequest(UserInfo userInfo, SaLoginParameter loginModel) { setLocalLoginUser(userInfo); String token = StpUtil.createLoginSession(splicingLoginId(userInfo.getUserId()), loginModel); userInfo.setToken(TOKEN_PREFIX_SP + token); setLoginUser(userInfo); } // =================== 登录用户ID相关操作 =================== /** * 获取指定TOKEN用户ID * * @param token * @return */ public static String getLoginUserId(String token) { String loginId = (String) StpUtil.getLoginIdByToken(token); return parseLoginId(loginId); } /** * 获取当前用户ID, 包含临时切换用户ID * * @return */ public static String getLoginUserId() { String loginId = getUser().getUserId(); return parseLoginId(loginId); } // =================== 用户ID拼接相关操作 =================== /** * 拼接租户下的用户ID * * @param userId * @return */ public static String splicingLoginId(String userId) { return splicingLoginId(userId, null); } /** * 拼接租户下的用户ID * @param userId * @param tenantId * @return */ private static String splicingLoginId(String userId, String tenantId) { if(StringUtil.isEmpty(tenantId)){ tenantId = TenantHolder.getDatasourceId(); } if (!StringUtil.isEmpty(tenantId)) { return tenantId + StrPool.COLON + userId; } return userId; } /** * 解析租户下的登录ID * @param loginId * @return */ private static String parseLoginId(String loginId) { if (loginId != null && loginId.contains(StrPool.COLON)) { loginId = loginId.substring(loginId.indexOf(StrPool.COLON) + 1); } return loginId; } /** * Token是否有效 * * @param token * @return */ public static Boolean isValidToken(String token) { UserInfo userInfo = getUser(token); return userInfo.getUserId() != null; } // =================== UserInfo缓存相关操作 =================== /** * 设置Redis用户数据 */ public static void setLoginUser(UserInfo userInfo) { StpUtil.getTokenSessionByToken(cutToken(userInfo.getToken())).set(USER_INFO_KEY, userInfo); } /** * 设置本地用户数据 */ public static void setLocalLoginUser(UserInfo userInfo) { USER_CACHE.set(userInfo); } /** * 获取本地用户数据 */ public static UserInfo getLocalLoginUser() { return USER_CACHE.get(); } /** * 清空本地用户数据 */ public static void clearLocalUser() { USER_CACHE.remove(); } /** * 获取用户缓存 * 保留旧方法 * * @param token * @return */ public UserInfo get(String token) { return UserProvider.getUser(token); } /** * 获取用户缓存 * * @return */ public UserInfo get() { return UserProvider.getUser(); } /** * 根据用户ID, 租户ID获取随机获取一个UserInfo * @param userId * @param tenantId * @return */ public static UserInfo getUser(String userId, String tenantId){ return getUser(userId, tenantId, null, null); } /** * 根据用户ID, 租户ID, 设备类型获取随机获取一个UserInfo * @param userId * @param tenantId * @param includeDevice 指定的设备类型中查找 * @param excludeDevice 排除指定设备类型 * @return */ public static UserInfo getUser(String userId, String tenantId, List includeDevice, List excludeDevice){ SaSession session = StpUtil.getSessionByLoginId(splicingLoginId(userId, tenantId), false); if (session != null) { List tokenSignList = session.getTerminalList(); if (!tokenSignList.isEmpty()) { tokenSignList = tokenSignList.stream().filter(tokenSign -> { if(!ObjectUtils.isEmpty(excludeDevice)){ if(excludeDevice.contains(tokenSign.getDeviceType())){ return false; } } if(!ObjectUtils.isEmpty(includeDevice)){ if(!includeDevice.contains(tokenSign.getDeviceType())){ return false; } } return true; }).collect(Collectors.toList()); if(!tokenSignList.isEmpty()){ return getUser(tokenSignList.get(0).getTokenValue()); } } } return new UserInfo(); } /** * 获取用户缓存 * * @param token * @return */ public static UserInfo getUser(String token) { UserInfo userInfo = null; String tokens = null; if (token != null) { tokens = cutToken(token); } else { try { //处理非Web环境报错 tokens = StpUtil.getTokenValue(); } catch (Exception e) { } } if (tokens != null) { if (StpUtil.getLoginIdByToken(tokens) != null) { userInfo = (UserInfo) StpUtil.getTokenSessionByToken(tokens).get(USER_INFO_KEY); } } if (userInfo == null) { userInfo = new UserInfo(); } return userInfo; } /** * 获取用户缓存 * * @return */ public static UserInfo getUser() { // if(StpUtil.getTokenValue() == null){ // return new UserInfo(); // } UserInfo userInfo = USER_CACHE.get(); if (userInfo != null) { return userInfo; } userInfo = UserProvider.getUser(null); if (userInfo.getUserId() != null) { USER_CACHE.set(userInfo); } return userInfo; } // =================== Token相关操作 =================== /** * 去除Token前缀 * * @param token * @return */ public static String cutToken(String token) { if (token != null && token.startsWith(TOKEN_PREFIX_SP)) { token = token.substring(TOKEN_PREFIX_SP.length()); } return token; } /** * 获取token */ public static String getToken() { String toke = getAuthorize(); return toke; } /** * 获取Authorize */ public static String getAuthorize() { String authorize = ServletUtil.getHeader(Constants.AUTHORIZATION); return authorize; } /** * TOKEN续期 */ public static void renewTimeout(String token) { if (StpUtil.getTokenValue() != null) { UserInfo userInfo = UserProvider.getUser(token); if(userInfo.getUserId() == null || userInfo.getTokenTimeout() == null) { //避免请求过网关之后TOKEN失效(携带TOKEN调用登录接口之后账号被顶替) return; } StpUtil.renewTimeout(userInfo.getTokenTimeout() * 60L); if(userInfo.getIsAdministrator()) { SaSession saSession = StpUtil.getSessionByLoginId(splicingLoginId(Constants.ADMIN_KEY), false); if (saSession != null) { saSession.updateTimeout(userInfo.getTokenTimeout() * 60L); } } } } /** * 获取所有Token记录 * 包含无效状态的用户、临时用户 * * @return */ public static List getLoginUserListToken() { return StpUtil.searchTokenValue("", -1, -1, true).stream().map(token -> token.replace(StpUtil.stpLogic.splicingKeyTokenValue(""), "")).collect(Collectors.toList()); } // =================== 临时Token相关操作 =================== /** * 获取内部服务传递验证TOKEN * * @return */ public static String getInnerAuthToken() { return SaSameUtil.getToken(); } /** * 验证内部传递Token是否有效 抛出异常 * @param token */ public static void checkInnerToken(String token){ SaSameUtil.checkToken(token); } /** * 验证内部传递Token是否有效 * @param token */ public static boolean isValidInnerToken(String token){ return SaSameUtil.isValid(token); } // =================== 退出相关操作 =================== /** * 根据用户ID踢出全部用户 * @param userId */ public static void kickoutByUserId(String userId, String tenantId) { StpUtil.kickout(splicingLoginId(userId, tenantId)); } /** * 根据Token踢出指定会话 * @param tokens */ public static void kickoutByToken(String... tokens) { for (String token : tokens) { StpUtil.kickoutByTokenValue(token); } } /** * 退出当前Token, 不清除用户其他系统缓存 */ public static void logout() { StpUtil.logout(); } /** * 退出指定Token, 不清除用户其他系统缓存 * * @param token */ public static void logoutByToken(String token) { if (token == null) { logout(); } else { StpUtil.logoutByTokenValue(cutToken(token)); } } /** * 退出指定设备类型的用户的全部登录信息, 不清除用户其他系统缓存 * * @param userId * @param deviceType */ public static void logoutByUserId(String userId, DeviceType deviceType) { StpUtil.logout(splicingLoginId(userId), deviceType.getDevice()); } /** * 退出指定用户的全部登录信息, 清除相关缓存 * * @param userId */ public static void logoutByUserId(String userId) { StpUtil.logout(splicingLoginId(userId)); removeOtherCache(userId); } // =================== 用户权限 =================== /** * 获取当前用户拥有的权限列表(菜单编码列表、功能ID列表) * @return */ public static List getPermissionList(){ return StpUtil.getPermissionList(); } /** * 获取当前用户拥有的角色列表 * @return */ public static List getRoleList(){ return StpUtil.getRoleList(); } // =================== 其他缓存相关操作 =================== /** * 移除 */ public static void removeOtherCache(String userId) { redisUtil.remove(cacheKeyUtil.getUserAuthorize() + userId); redisUtil.remove(cacheKeyUtil.getSystemInfo()); } /** * 是否在线 */ public boolean isOnLine(String userId) { return StpUtil.getTokenValueByLoginId(splicingLoginId(userId), getDeviceForAgent().getDevice()) != null; } /** * 是否登陆 */ public static boolean isLogined() { return StpUtil.isLogin(); } /** * 指定Token是否有效 * @param token * @return */ public static boolean isValid(String token) { return StpUtil.getLoginIdByToken(token) != null; } public static DeviceType getDeviceForAgent() { if (ServletUtil.getIsMobileDevice()) { return DeviceType.APP; } else { return DeviceType.PC; } } /** * 判断用户是否是临时用户 * @param userInfo * @return */ public static boolean isTempUser(UserInfo userInfo){ if(userInfo == null){ userInfo = getUser(); } return DeviceType.TEMPUSER.getDevice().equals(userInfo.getLoginDevice()) || DeviceType.TEMPUSERLIMITED.getDevice().equals(userInfo.getLoginDevice()); } }