zf
2024-03-25 cd02923a7ce1ffa004b3abbb7af67ab6173dd99d
safePlatfrom-out-web/src/main/java/com/gkhy/safePlatform/config/security/TokenAuthenticationFilter.java
@@ -10,6 +10,7 @@
import com.gkhy.safePlatform.commons.enums.ResultCodes;
import com.gkhy.safePlatform.commons.exception.BusinessException;
import com.gkhy.safePlatform.commons.utils.RPCUtils;
import com.gkhy.safePlatform.commons.utils.RequestContextHolder;
import com.gkhy.safePlatform.commons.utils.StringUtils;
import com.gkhy.safePlatform.commons.vo.ResultVO;
import com.gkhy.safePlatform.config.redis.RedisUtils;
@@ -29,6 +30,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
@@ -68,97 +70,77 @@
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest req,HttpServletResponse resp) {
        // header获取token
        String authToken = req.getHeader(tokenConfig.getHeader());
        String loginUserId = req.getHeader(tokenConfig.getLoginUserHeader());
        if(authToken != null) {
            // header 传入 userId
            if (StringUtils.isBlank(loginUserId)) {
                throw new BusinessException(ResultCodes.CLIENT_CREDENTIALS_LACK);
            }
            // 登录成功时,会将权限数据存入redis
            // 这里是验证获取权限信息
            // 1.从redis中获取对应该用户的权限信息
            String accessTokenKey = RedisKeyEnum.authKey(RedisKeyEnum.AUTH_TOKEN, loginUserId);
            String accessTokenKey = RedisKeyEnum.authKey(RedisKeyEnum.AUTH_TOKEN, authToken);
            Object o = redisUtils.get(accessTokenKey);
            // 2.token是否存在
            if (o == null) {
                // 是否存在
                // 是否存在 uid未登录
                throw new BusinessException(ResultCodes.CLIENT_CREDENTIALS_TOKEN_INVALID);
            }else{
                Long userId = Long.valueOf(loginUserId);
                ContextCacheUser contextCacheUser = JSONObject.parseObject(o.toString(), ContextCacheUser.class);
                assert userId.equals(contextCacheUser.getUid());
                if ( !authToken.equals(contextCacheUser.getAccessToken())) {
                    throw new BusinessException(ResultCodes.CLIENT_CREDENTIALS_TOKEN_INVALID);
                // todo 可以不转换,建议rpc传入string
                String uid = o.toString();
                Long userId = Long.valueOf(uid);
                String accessUserKey = RedisKeyEnum.authKey(RedisKeyEnum.AUTH_USER, userId);
                // 这里不做用户信息的token判断 放入登录
                Long expireSecondsLeft = redisUtils.getExpireTime(accessTokenKey);
                // 60m 内请求则续期 时长为原本的有效时间
                if (expireSecondsLeft != null && 0L < expireSecondsLeft && expireSecondsLeft < 60 * 60) {
                    // 重置token:uid
                    redisUtils.resetKeyExpireTime(accessTokenKey, tokenConfig.getExpiration());
                    // 重置uid:userInfo
                    redisUtils.resetKeyExpireTime(accessUserKey, tokenConfig.getExpiration());
                }
                // 3.redis获取权限
                String authoritiesKey = RedisKeyEnum.authKey(RedisKeyEnum.AUTH_AUTHORITIES, userId);
                Object oo = redisUtils.get(authoritiesKey);
                List<GrantedAuthority> authorities = new ArrayList<>();
                // 4.redis中是否存在
                if (oo != null) {
                    // 5.存在
                    List<ContextCacheAuthority> cacheAuthorities = JSONArray.parseArray(oo.toString(), ContextCacheAuthority.class);
                    for (ContextCacheAuthority cacheAuthority: cacheAuthorities) {
                        authorities.add(new SimpleGrantedAuthority(cacheAuthority.getAuthority()));
                    }
                }else {
                    // 6.不存在=>数据库查询
                    ResultVO<String> rpcResultRole = userAccountService.getUserRoleCodeByUserId(userId);
                    if (rpcResultRole == null) {
                        throw new BusinessException(ResultCodes.RPC_RESULT_NULL);
                    }
                    if (!ResultCodes.OK.getCode().equals(rpcResultRole.getCode())) {
                        throw new BusinessException(rpcResultRole.getCode(), rpcResultRole.getMsg());
                    }
                    if (rpcResultRole.getData() == null) {
                        throw new BusinessException(ResultCodes.RPC_DATA_NULL);
                    }
                    if (!(rpcResultRole.getData() instanceof String)) {
                        throw new BusinessException(ResultCodes.RPC_DATA_TYPE_NOT_MATCH);
                    }
                    // role
                    authorities.add(new SimpleGrantedAuthority("ROLE_" + rpcResultRole.getData().toString()));
                    // permission
                    ResultVO<List<String>> rpcResultPermission = userAccountService.getUserPermissionByUserId(userId);
                    if (rpcResultPermission == null) {
                        throw new BusinessException(ResultCodes.RPC_RESULT_NULL);
                    }
                    if (!ResultCodes.OK.getCode().equals(rpcResultPermission.getCode())) {
                        throw new BusinessException(rpcResultRole.getCode(), rpcResultRole.getMsg());
                    }
                    if (rpcResultPermission.getData() == null) {
                        throw new BusinessException(ResultCodes.RPC_DATA_NULL);
                    }
                    if (!(rpcResultPermission.getData() instanceof List)) {
                        throw new BusinessException(ResultCodes.RPC_DATA_TYPE_NOT_MATCH);
                    }
                    List<String> permissions = RPCUtils.castList(rpcResultPermission.getData(), String.class);
                    for (String permission : permissions) {
                        SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(permission);
                        authorities.add(simpleGrantedAuthority);
                    }
                // 获取用户信息
                Object oo = redisUtils.get(accessUserKey);
                // 初始化
                ContextCacheUser contextCacheUser = null;
                if (oo == null) {
                    // 业务逻辑上是不会空的
                    // 实际操作可能会手动清空
                    ResultVO<ContextCacheUser> rpcResultVo = userAccountService.getCacheUserDetailByUid(userId);
                    // 调用rpc返回的数据 没有token 所以得至少续上这次token
                    contextCacheUser = this.getRpcResult(rpcResultVo);
                    // 因为手动清空等原因,可能会丢失其他token数据,就不去一一搜索这个uid的token了
                    contextCacheUser.setAccessToken(Collections.singletonList(authToken));
                }else{
                    // 正常的实际场景必定会走这里
                    // 推荐用jackson
                    contextCacheUser = JSONObject.parseObject(oo.toString(), ContextCacheUser.class);
                }
                // threadLocal存入用户信息
                RequestContextHolder.contextUserLocal.set(contextCacheUser);
                // security对象中存入登陆者信息
                return new UsernamePasswordAuthenticationToken(contextCacheUser,authToken,authorities);
                return new UsernamePasswordAuthenticationToken(contextCacheUser, authToken, contextCacheUser.getAuthorities());
            }
        }
        return null;
    }
    /**
     * 获取rpc 返回的用户数据
     *
     * @param rpcResultVo rpc返回数据
     * @return 用户准备缓存的数据
     */
    private ContextCacheUser getRpcResult(ResultVO<ContextCacheUser> rpcResultVo) {
        if (!rpcResultVo.getCode().equals(ResultCodes.OK.getCode())) {
            throw new BusinessException(rpcResultVo.getCode(), rpcResultVo.getMsg());
        }
        if (rpcResultVo.getData() == null) {
            throw new BusinessException(ResultCodes.RPC_DATA_NULL);
        }
        if (rpcResultVo.getData() instanceof ContextCacheUser) {
            return (ContextCacheUser) rpcResultVo.getData();
        } else {
            throw new BusinessException(ResultCodes.RPC_DATA_TYPE_NOT_MATCH);
        }
    }
    protected void writeJSON(HttpServletRequest req,