zullフィルタ

18879 ワード


一、機能点
(1)特定のパスを指し示すフィルタリング不要
例えばログインインタフェース、辞書インタフェース、
(2)tokenチェック
redisによってtoken検証を実現し、失効:token検証に失敗した.有効:有効期限の延長
(3)鑑識権
権限ツリーに基づいて要求されたurlが合法かどうかを検証します.
(4)パッケージ要求データ
二、コード
(1)フィルタ
@RefreshScope
public class AccessFilter extends ZuulFilter {
	private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
	
	@Autowired
	private HystrixWrappedAuthServiceClient hystrixWrappedAuthServiceClient;
	
	@Value("${timestamp.validate.limit:180}")
	private String validateLimit;
	@Override
	public String filterType() {
		return "pre";
	}
	@Override
	public int filterOrder() {
		return 0;
	}
	@Override
	public boolean shouldFilter() {
		return true;
	}
    
	@Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        log.info(String.format("    IP  %s    %s request to %s", getIpAddr(request), request.getMethod(), request.getRequestURL().toString()));
        log.info("url is :" + request.getRequestURL().toString());
        if (skipAllFilters(request.getRequestURL().toString())) {
            log.info("      ");
            return null;
        }
        String url = request.getRequestURL().toString();
        log.info("    .....url:{}",url);
        //          token    ,       token      
        if (containUpload(url)) {
        	String token = request.getParameter("token");
        	if (!validateToken(url, token)) {
                ZuulResponseModel responseModel = new ZuulResponseModel();
                log.warn("token    ");
                responseModel.setRepCode(RespCode.ZUUL_TOKEN_ERROR);
                responseModel.setRepMsg("token    ");
                ctx = getContextForError(ctx, responseModel);
                return null;
            }
        	ZuulRequestModel requestModel=new ZuulRequestModel();
			requestModel.setUrl(url);
			requestModel.setAuthUrl(request.getServletPath());
			requestModel.setToken(token);
        	if (!validateAuth(requestModel)) {
                ZuulResponseModel responseModel = new ZuulResponseModel();
                log.warn("      ");
                responseModel.setRepCode(RespCode.ZUUL_AUTH_ERROR);
                responseModel.setRepMsg(RespMsg.ZUUL_AUTH_ERROR_MSG);
                ctx = getContextForError(ctx, responseModel);
                return null;
            }
        	log.info("        ");
            return null;
        }
        ZuulResponseModel parameterCheckResult = validateWithParameters(request);
        if (null != parameterCheckResult) {
            if (RespCode.SUCCESS == parameterCheckResult.getRepCode()) {
                return null;
            } else {
                ctx = getContextForError(ctx, parameterCheckResult);
                return null;
            }
        }
        //        token
        String jsonStr = getData(request);
        JSONObject jsonData = JSONObject.parseObject(jsonStr);
        ZuulRequestModel requestModel;
        ZuulRequestArrayModel requestArrayModel = null;
        try {
            requestModel = JSON.parseObject(jsonData.toString(), ZuulRequestModel.class);
        } catch (Exception e) {
            requestArrayModel=JSON.parseObject(jsonData.toString(), ZuulRequestArrayModel.class);
            requestModel=new ZuulRequestModel();
            requestModel.setAuthUrl(requestArrayModel.getAuthUrl());
            requestModel.setJsonStr(requestArrayModel.getJsonStr());
            requestModel.setSign(requestArrayModel.getSign());
            requestModel.setTime(requestArrayModel.getTime());
            requestModel.setToken(requestArrayModel.getToken());
            requestModel.setUrl(requestArrayModel.getUrl());
            requestModel.setUserId(requestArrayModel.getUserId());
        }
        requestModel.setJsonStr(jsonStr);
        requestModel.setUrl(url);
        requestModel.setAuthUrl(request.getServletPath());
        if (!validateToken(url, requestModel.getToken())) {
            ZuulResponseModel responseModel = new ZuulResponseModel();
            log.warn("token    ");
            responseModel.setRepCode(RespCode.ZUUL_TOKEN_ERROR);
            responseModel.setRepMsg("token    ");
            ctx = getContextForError(ctx, responseModel);
            return null;
        }
        log.debug("  token  ");
//        //TODO     ,       ,         
//        String[] tokenInfo = requestModel.getToken().split("_");
//        if (!Pattern.matches("w.*", tokenInfo[0])) {
//        	return null;
//        }
        if (!validateAuth(requestModel)) {
            ZuulResponseModel responseModel = new ZuulResponseModel();
            log.warn("      ");
            responseModel.setRepCode(RespCode.ZUUL_AUTH_ERROR);
            responseModel.setRepMsg(RespMsg.ZUUL_AUTH_ERROR_MSG);
            ctx = getContextForError(ctx, responseModel);
            return null;
        }
        log.debug("      ");
        return null;
        
    }

	private boolean containUpload(String url) {
		if (Pattern.matches(".*/upload", url)) {
			return true;
		}
		return false;
	}
	private String getData(HttpServletRequest req) {
		String result = null;
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream) req.getInputStream(), "utf-8"));
			StringBuffer sb = new StringBuffer("");
			String line;
			while ((line = br.readLine()) != null) {
				sb.append(line);
			}
			br.close();
			result = sb.toString();
			log.info("  data   " + result);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return result;
	}

	private String getIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	private boolean validateToken(String url, String token) {
		log.info("validateToken  ()");
		log.info("  : {url:" + url + ",token:" + token + "}");
		boolean isValid = false;
		if (Pattern.matches(".*/noauth/.*|.*/login/.*", url)) { //   token  
			return true;
		}
		if (null == token || "".equals(token.trim())) {
			log.warn("token is null");
			log.info("token is null");
			isValid = false;
		}
		isValid = hystrixWrappedAuthServiceClient.validate(token);
		log.warn("token:" + token + "----- isValid :" + isValid);
		log.info("validateToken()  ,isValid:" + isValid);
		return isValid;
	}

	private RequestContext getContextForError(RequestContext ctx, ZuulResponseModel responseModel) {
		RequestContext requestContext = ctx;
		ctx.setResponseBody(responseModel.toJsonString());
		ctx.setSendZuulResponse(false);
		ctx.getResponse().setContentType("text/html;charset=UTF-8");
		ctx.getResponse().setContentType(String.valueOf(MediaType.APPLICATION_JSON));
		return requestContext;
	}

	private boolean skipAllFilters(String requestUrl) {
		boolean isSkip = false;
		if (Pattern.matches(".*/noauth/.*|.*/dict/.*", requestUrl)) {
			isSkip = true;
		}
		return isSkip;
	}

    @SuppressWarnings("static-access")
	private ZuulResponseModel validateWithParameters(HttpServletRequest request) {
        if (!Pattern.matches(".*/exportInfoByExcel|.*/exportVehicleByExcel|.*/storagePlan/importTemplateDownload|.*/order/exportInfoByExcel|.*/stock/exportInfoByExcel", request.getRequestURL())) {
            return null;
        }
        ZuulResponseModel responseModel = new ZuulResponseModel();
        Map params = request.getParameterMap();
        StringBuffer parameterbf = new StringBuffer();
        Iterator> paramsEntryI = params.entrySet().iterator();
        while (paramsEntryI.hasNext()) {
            Entry e = paramsEntryI.next();
            String[] values = e.getValue();
            for (int i = 0; i < values.length; i++) {
                String value = values[i];
                parameterbf.append(e.getKey()).append("=").append(value).append("&");
            }
        }
        log.info("--------------parameter in url is: " + parameterbf.toString());

        String[] timeValues = params.get("time");
        if (null != timeValues && timeValues.length == 1) {
            Timestamp nowTime = new Timestamp(System.currentTimeMillis());
            Timestamp requestTime = new Timestamp(Long.parseLong(timeValues[0]));
            log.info("       :" + Integer.parseInt(validateLimit));
            if (Math.abs(nowTime.getTime() / 1000 - requestTime.getTime()) > Integer.parseInt(validateLimit)) {
                log.warn("        ");
                responseModel.setRepCode(RespCode.ZUUL_TIMESTAMP_ERROR);
                responseModel.setRepMsg(RespMsg.ZUUL_TIMESTAMP_ERROR_MSG);
                return responseModel;
            }
            responseModel.setRepCode(RespCode.SUCCESS);
            log.debug("       ");
            return responseModel;
        }
        String[] tokens = params.get("token");
        String[] signs = params.get("sign");
        String baseSignMsg = "time=" + timeValues[0] + "&token=" + tokens[0];
        log.info("----------------------------base sign message is:(" + baseSignMsg + ")------");
        log.info("----------------------------encrypt sign message is:(" + MD5Util.getInstance().encrypt(baseSignMsg) + ")------");
        if (null != signs && 1 <= signs.length) {
            log.info("----------------------------received sign message is:(" + signs[0] + ")------");
        }
        if (null == signs || 1 != signs.length || !MD5Util.getInstance().encrypt(baseSignMsg).equalsIgnoreCase(signs[0])) {
            log.warn("sign    ");
            responseModel.setRepCode(RespCode.ZUUL_SIGN_ERROR);
            responseModel.setRepMsg("");
            return responseModel;
        }
        log.info("----------------------------sign is valid!------");
        return null;
    }

	//   
	private boolean validateAuth(ZuulRequestModel requestModel) {
		boolean isValid = false;
		if (Pattern.matches(".*/noauth/.*", requestModel.getUrl())) {
			return true;
		}
		log.info(requestModel.getUserId());
		log.info(requestModel.getAuthUrl());
		String userId = requestModel.getUserId();
		String authUrl = requestModel.getAuthUrl();
		log.info("    ......authUrl={},userId={}",authUrl,userId);
		if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(authUrl)) {
			return isValid;
		}
		return hystrixWrappedAuthServiceClient.validateByUrl(Long.valueOf(userId), authUrl);
	}

(2)token検証実装
token検証ロジックは別の権限サービスにあるため、サービス間呼び出しが必要です.
   @RequestMapping("/token/validate")
	public boolean validateToken(@RequestParam("token") String token) {
		return userService.validateToken(token);
	}
	@Override
	public boolean validateToken(String token) {
		TokenEntity tokenModel = tokenManager.getToken(token);
		logger.info("validateToken(){}=====tokenModel:" + tokenModel);
		boolean isValidate = tokenManager.checkToken(tokenModel);
		logger.info("validateToken(){}=====isValidate:" + isValidate);
		return isValidate;
	}

tokenエンティティ、key指定文字列+userId
public class TokenEntity {

	private static final String LOGIN_TOKEN_PREFIX = "LOGIN_TOKEN_USER_";

	//    id
	private Long userId;

	//       uuid
	private String token;

	// redis key
	private String redisKey;

	public TokenEntity(Long userId, String token) {
		this.userId = userId;
		this.token = token;
		this.redisKey = LOGIN_TOKEN_PREFIX + userId;
	}

	/**
	 * Getter method for property userId.
	 * 
	 * @return property value of userId
	 */
	public Long getUserId() {
		return userId;
	}

	/**
	 * Setter method for property userId.
	 * 
	 * @param userId value to be assigned to property userId
	 */
	public void setUserId(Long userId) {
		this.userId = userId;
	}

	/**
	 * Getter method for property token.
	 * 
	 * @return property value of token
	 */
	public String getToken() {
		return token;
	}

	/**
	 * Setter method for property token.
	 * 
	 * @param token value to be assigned to property token
	 */
	public void setToken(String token) {
		this.token = token;
	}

	/**
	 * Getter method for property redisKey.
	 * 
	 * @return property value of redisKey
	 */
	public String getRedisKey() {
		return redisKey;
	}

	/**
	 * Setter method for property redisKey.
	 * 
	 * @param redisKey value to be assigned to property redisKey
	 */
	public void setRedisKey(String redisKey) {
		this.redisKey = redisKey;
	}

}

token実装クラス作成、検証、取得、削除
@Service
public class RedisTokenManager implements TokenManager {

	private static Logger logger = LoggerFactory.getLogger(RedisTokenManager.class);

	@Autowired
	private RedisUtils redisUtils;

	@Value("${token.timeout.second:1800}")
	private String timeout;

	/**
	 * @param userId
	 * @return
	 * @see com.anji.allways.business.user.service.TokenManager#createToken(java.lang.Long)
	 */
	@Override
	public TokenEntity createToken(Long userId, String userName) {
		logger.info("createToken  ");
		logger.info("  :userId{}" + userId + ",userName{}" + userName);
		//    uuid     token
		String token = userName + "_" + userId + "_" + UUIDUtil.getInstance().getUUID32();
		TokenEntity tokenModel = new TokenEntity(userId, token);
		//     redis        
		logger.info("tokenModel{}" + tokenModel.toString());
		redisUtils.set(tokenModel.getRedisKey(), tokenModel.getToken(), Integer.parseInt(timeout));
		logger.info("createToken  ");
		return tokenModel;
	}

	/**
	 * @param token
	 * @return
	 * @see com.anji.allways.business.user.service.TokenManager#checkToken(com.anji.allways.business.user.entity.TokenEntity)
	 */
	@Override
	public boolean checkToken(TokenEntity tokenModel) {
		logger.info("checkTokne  ");
		if (tokenModel == null) {
			return false;
		}
		logger.info("tokenModel{}" + tokenModel.toString());
		String token = redisUtils.get(tokenModel.getRedisKey());
		logger.info("token{}" + token);
		if (token == null || !token.equals(tokenModel.getToken())) {
			return false;
		}
		//       ,              ,   token      
		logger.info("key{}" + tokenModel.getRedisKey() + ",value:{}" + redisUtils.get(tokenModel.getRedisKey()));
		redisUtils.set(tokenModel.getRedisKey(), redisUtils.get(tokenModel.getRedisKey()),
				Integer.parseInt(timeout));
		logger.info("checkTokne  ");
		return true;
	}

	/**
	 * @param authentication
	 * @param platform
	 * @return
	 * @see com.anji.allways.business.user.service.TokenManager#getToken(java.lang.String)
	 */
	@Override
	public TokenEntity getToken(String authentication) {
		if (null == authentication) {
			return null;
		}
		String[] param = authentication.split("_");
		if (param.length != 5 && param.length != 3) {
			return null;
		}
		//    userId    token        token,        
		Long userId = Long.parseLong(param[1]);
		String token = authentication;
		return new TokenEntity(userId, token);
	}

	/**
	 * @param userId
	 * @see com.anji.allways.business.user.service.TokenManager#deleteToken(java.lang.Long)
	 */
	@Override
	public void deleteToken(TokenEntity tokenModel) {
		redisUtils.del(tokenModel.getRedisKey());
	}

	/**
	 * @param userVO
	 * @return
	 * @see com.anji.allways.business.auth.service.TokenManager#createToken(com.anji.allways.business.auth.vo.UserVO)
	 */
	@Override
	public TokenEntity createToken(UserVO userVO) {
		logger.info("createToken  ");
		//    uuid     token
		String token = userVO.getUserName() + "_" + userVO.getId() + "_"+ userVO.getUserType() +"_"+ userVO.getBelongTo() +"_" +UUIDUtil.getInstance().getUUID32();
		TokenEntity tokenModel = new TokenEntity(userVO.getId(), token);
		logger.info("tokenModel{}",tokenModel.toString());
		//     redis        
		redisUtils.set(tokenModel.getRedisKey(), tokenModel.getToken(), Integer.parseInt(timeout));
		logger.info("createToken:  ");
		return tokenModel;
	}

}

(3)認証の実現
 
  @RequestMapping("/validate/url")
    public boolean validateByUrl(Long userId, String authUrl) {
    	logger.info("userId={},authUrl={}",userId,authUrl);
        return authService.queryAuthByUrl(userId,authUrl);
    }
@Service
@Transactional
public class AuthServiceImpl extends AbstractService implements AuthService {

	@Autowired
	private AuthMapper authMapper;

	@Override
	public CommonMapper getCommonMapper() {
		return authMapper;
	}
	
	@Override
	public boolean queryAuthByUrl(Long userId, String url) {
		List auths = authMapper.queryAuthByUrl(userId);
		if(CollectionUtils.isEmpty(auths)) {
			return false;
		}
		for (AuthEntity authEntity : auths) {
			if(url.contains(authEntity.getUrl())) {
				return true;
			}
		}
		return false;
	}
}

ユーザー権限sqlの取得