ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

base-api-gateway - 代码7

2022-07-27 12:31:41  阅读:138  来源: 互联网

标签:return String request api base BmsBaseResponse import com gateway


package com.hihonor.honorhome.component.apigateway.handler;

import com.hihonor.honorhome.common.response.BmsBaseResponse;

import javax.servlet.http.HttpServletRequest;

/**
 * 请求重复校验处理
 */
public interface RepeatRequestHandler {
    /**
     * 请求重复校
     * @param request HttpServletRequest
     * @return BmsBaseResponse
     */
    BmsBaseResponse checkRandomRequestId(HttpServletRequest request);
}
package com.hihonor.honorhome.component.apigateway.handler.impl;

import com.hihonor.honorhome.common.component.RedisKeyBuilder;
import com.hihonor.honorhome.common.response.BmsBaseResponse;
import com.hihonor.honorhome.component.apigateway.common.Constants;
import com.hihonor.honorhome.component.apigateway.common.HeaderConstant;
import com.hihonor.honorhome.component.apigateway.common.ResponseEnum;
import com.hihonor.honorhome.component.apigateway.handler.RepeatRequestHandler;

import com.alibaba.nacos.api.config.annotation.NacosValue;

import io.lettuce.core.RedisConnectionException;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;

/**
 * 请求重复校验处理
 */
@Slf4j
@Component
public class DefaultRepeatRequestHandler implements RepeatRequestHandler {
    @NacosValue(value = "${request.expiration.time}", autoRefreshed = true)
    private int expirationTime;

    @NacosValue(value = "${request.min.retry}", autoRefreshed = true)
    private Integer requestMinRetry;

    @NacosValue(value = "${request.max.retry}", autoRefreshed = true)
    private Integer requestMaxRetry;

    @NacosValue(value = "${honorhome-apigateway.compatible.version}", autoRefreshed = true)
    private String[] versions;

    @Autowired
    private RedisKeyBuilder gatewayRedisKeyBuilder;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public BmsBaseResponse checkRandomRequestId(HttpServletRequest request) {
        String appVersionName = request.getHeader(HeaderConstant.HEADER_APP_VERSION_NAME);
        if (StringUtils.isBlank(appVersionName)) {
            return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-app-version-name is empty!");
        }
        String requestNonce = getRequestNonce(request, appVersionName);
        if (StringUtils.isBlank(requestNonce)) {
            return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-request-nonce is empty!");
        }
        String timestamp = request.getHeader(HeaderConstant.HEADER_TIMESTAMP);
        if (StringUtils.isBlank(timestamp)) {
            return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-timestamp is empty!");
        }
        String redisKey = String.format(Locale.ROOT, "API-GATEWAY:%s", requestNonce + ":" + timestamp);
        String key = gatewayRedisKeyBuilder.buildKey(Constants.BUSINESS_NAME, Constants.REQUEST_NAME, redisKey);
        try {
            String redisValue = stringRedisTemplate.opsForValue().get(key);
            if (redisValue == null) {
                String requestValue = String.valueOf(requestMinRetry);
                // 如果不存在,说明第一次请求,直接插入
                stringRedisTemplate.opsForValue().set(key, requestValue, expirationTime, TimeUnit.SECONDS);
            } else {
                Integer valueFrequency = Integer.parseInt(redisValue) + 1;
                log.warn("{}: retry times {}", requestNonce, valueFrequency);
                log.warn("url: {}", request.getRequestURL());
                if (valueFrequency > requestMaxRetry) {
                    log.error("{}: retry more than three times in 15 minute", key);
                    return BmsBaseResponse.error(ResponseEnum.REQUEST_RETRY_FAILED);
                }
                stringRedisTemplate.opsForValue().set(key, String.valueOf(valueFrequency), 0);
            }
            return BmsBaseResponse.OK;
        } catch (RedisConnectionException e) {
            log.error("checkRandomRequestId redis connect error", e);
            return new BmsBaseResponse(ResponseEnum.OK.getCode(), ResponseEnum.OK.getEnMessage());
        } catch (Exception e) {
            log.error("checkRandomRequestId handle error", e);
            return BmsBaseResponse.error(ResponseEnum.ERROR);
        }
    }

    private String getRequestNonce(HttpServletRequest request, String appVersionName) {
        String requestNonce;
        List<String> versionList = Arrays.asList(versions);
        if (!CollectionUtils.isEmpty(versionList) && versionList.contains(appVersionName)) {
            requestNonce = StringUtils.isBlank(request.getHeader(HeaderConstant.HEADER_REQUEST_NONCE))
                ? request.getHeader(HeaderConstant.HEADER_REQUEST_ID)
                : request.getHeader(HeaderConstant.HEADER_REQUEST_NONCE);
        } else {
            requestNonce = request.getHeader(HeaderConstant.HEADER_REQUEST_NONCE);
        }
        return requestNonce;
    }
}
package com.hihonor.honorhome.component.apigateway.handler;

import com.hihonor.honorhome.common.response.BmsBaseResponse;

import javax.servlet.http.HttpServletRequest;

/**
 * 功能描述:
 * 校验REQUEST HEADER
 */
public interface RequestHeaderHandler {
    /**
     * 检查REQUEST HEADER中的参数
     *
     * @param request request
     * @return 校验是否通过的标识
     */
    BmsBaseResponse checkHeader(HttpServletRequest request);
}
package com.hihonor.honorhome.component.apigateway.handler.impl;

import com.hihonor.honorhome.common.constants.NumberConstant;
import com.hihonor.honorhome.common.response.BmsBaseResponse;
import com.hihonor.honorhome.component.apigateway.common.HeaderConstant;
import com.hihonor.honorhome.component.apigateway.common.ResponseEnum;
import com.hihonor.honorhome.component.apigateway.handler.RequestHeaderHandler;

import com.alibaba.nacos.api.config.annotation.NacosValue;

import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

/**
 * 功能描述:
 *  校验REQUEST HEADER
 *
 * @author zw0067467
 * @since 2022-06-10
 */
public class DefaultRequestHeaderHandler implements RequestHeaderHandler {
    @NacosValue(value = "${honorhome-apigateway.compatible.version}", autoRefreshed = true)
    private String[] versions;

    private final Set<String> countrySet = new HashSet<>();

    /**
     * 初始化countrySet
     */
    @PostConstruct
    public void init() {
        // 国家
        String[] countryCodes = Locale.getISOCountries();
        if (countryCodes.length > 0) {
            for (String countryCode : countryCodes) {
                if (StringUtils.isBlank(countryCode)) {
                    continue;
                }
                countrySet.add(countryCode);
            }
        }
    }

    /**
     * 检查REQUEST HEADER中的参数
     *
     * @param request request
     * @return 校验是否通过的标识
     */
    @Override
    public BmsBaseResponse checkHeader(HttpServletRequest request) {
        String appVersionName = request.getHeader(HeaderConstant.HEADER_APP_VERSION_NAME);
        if (StringUtils.isBlank(appVersionName)) {
            return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-app-version-name is empty!");
        }
        if (appVersionName.length() > NumberConstant.NUMBER_64) {
            return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-app-version-name is too long!");
        }
        String requestNonce = getRequestNonce(request, appVersionName);
        if (StringUtils.isBlank(requestNonce)) {
            return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-request-nonce is empty!");
        }
        String country = request.getHeader(HeaderConstant.HEADER_COUNTRY);
        if (StringUtils.isBlank(country)) {
            return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-country is empty!");
        }
        if (!isValidCountry(country)) {
            return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-country is invalid!");
        }
        return checkHeaderParam(request);
    }

    /**
     * 校验国家简称是否符合ISO3166标准
     *
     * @param country 国家简称
     * @return 是否符合ISO标准
     */
    private boolean isValidCountry(String country) {
        return countrySet.contains(country);
    }

    /**
     * 请求头参数校验
     *
     * @param request Http请求
     * @return 是否符合校验规则
     */
    private BmsBaseResponse checkHeaderParam(HttpServletRequest request) {
        String userId = request.getHeader(HeaderConstant.HEADER_USER_ID);
        if (StringUtils.isNotBlank(userId)) {
            try {
                Base64.Decoder decoder = Base64.getDecoder();
                String user = new String(decoder.decode(userId), StandardCharsets.UTF_8);
                if (user.length() > NumberConstant.NUMBER_64) {
                    return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-user-id is too long!");
                }
            } catch (IllegalArgumentException e) {
                return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-user-id is illegal!");
            }
        }

        String udid = request.getHeader(HeaderConstant.HEADER_UDID);
        if (StringUtils.isNotBlank(udid)) {
            try {
                Base64.Decoder decoder = Base64.getDecoder();
                decoder.decode(udid);
            } catch (IllegalArgumentException e) {
                return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-udid is illegal!");
            }
        }

        String appId = request.getHeader(HeaderConstant.HEADER_APP_ID);
        if (StringUtils.isBlank(appId)) {
            return new BmsBaseResponse(ResponseEnum.BAD_REQUEST.getCode(), "x-app-id is empty!");
        }
        return BmsBaseResponse.OK;
    }

    /**
     * 获取nonce参数,appVersionName符合条件,nonce为空的情况下会自动补全
     *
     * @param request request
     * @param appVersionName appVersionName
     * @return requestNonce
     */
    private String getRequestNonce(HttpServletRequest request, String appVersionName) {
        String requestNonce;
        List<String> versionList = Arrays.asList(versions);
        if (!CollectionUtils.isEmpty(versionList) && versionList.contains(appVersionName)) {
            requestNonce = StringUtils.isBlank(request.getHeader(HeaderConstant.HEADER_REQUEST_NONCE))
                ? request.getHeader(HeaderConstant.HEADER_REQUEST_ID)
                : request.getHeader(HeaderConstant.HEADER_REQUEST_NONCE);
        } else {
            requestNonce = request.getHeader(HeaderConstant.HEADER_REQUEST_NONCE);
        }
        return requestNonce;
    }
}
package com.hihonor.honorhome.component.apigateway.handler;

import javax.servlet.http.HttpServletRequest;

/**
 * 功能描述:
 * 设置TRACE_ID
 * 打印REQUEST 相关日志
 * @author zw0067467
 * @since 2022-06-10
 */
public interface RequestLogHandler {
    /**
     * 设置TRACE_ID
     * 打印REQUEST 相关日志
     *
     * @param request request
     */
    void logRequest(HttpServletRequest request);
}
package com.hihonor.honorhome.component.apigateway.handler.impl;

import com.hihonor.honorhome.component.apigateway.common.HeaderConstant;
import com.hihonor.honorhome.component.apigateway.handler.RequestLogHandler;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;

import javax.servlet.http.HttpServletRequest;

/**
 * 功能描述
 * 设置TRACE_ID
 * 打印REQUEST 相关日志
 */
@Slf4j
public class DefaultRequestLogHandler implements RequestLogHandler {
    /**
     * 将request_id作为trace_id
     */
    private static final String TRACE_ID_KEY = HeaderConstant.HEADER_REQUEST_ID;

    /**
     * 设置TRACE_ID
     * 处理REQUEST 相关的日志
     *
     * @param request request
     */
    @Override
    public void logRequest(HttpServletRequest request) {
        if (request == null) {
            log.error("request is null");
            return;
        }
        // 白名单请求不需要trace
        Object attribute = request.getAttribute(HeaderConstant.IS_WHITE_URL);
        // 不属于白名单才会进行tracing
        if (!(HeaderConstant.IS_WHITE_URL_TRUE_VALUE.equals(attribute))) {
            // 设置traceId
            String traceId = request.getHeader(TRACE_ID_KEY);
            if (StringUtils.isBlank(traceId)) {
                traceId = "NULL";
            }
            MDC.put(TRACE_ID_KEY, traceId);
        }

        log.info("receive request,uri:{}", request.getRequestURI());
    }
}
package com.hihonor.honorhome.component.apigateway.handler;

import com.hihonor.honorhome.common.response.BmsBaseResponse;

import javax.servlet.http.HttpServletRequest;

/**
 * 权限校验处理器
 */
public interface UserAuthHandler {
    /**
     * 权限校验
     * @param request HttpServletRequest
     * @return BaseResponse
     */
    BmsBaseResponse userAuth(HttpServletRequest request);
}
package com.hihonor.honorhome.component.apigateway.handler.impl;

import com.hihonor.honorhome.common.response.BmsBaseResponse;
import com.hihonor.honorhome.component.apigateway.common.Constants;
import com.hihonor.honorhome.component.apigateway.common.HeaderConstant;
import com.hihonor.honorhome.component.apigateway.common.ResponseEnum;
import com.hihonor.honorhome.component.apigateway.handler.UserAuthHandler;
import com.hihonor.honorhome.component.apigateway.utils.TokenUtils;

import com.alibaba.nacos.api.config.annotation.NacosValue;

import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

/**
 * 权限校验处理器
 */
@Slf4j
@Component
public class DefaultUserAuthHandler implements UserAuthHandler {
    @NacosValue(value = "${auth.appIds}", autoRefreshed = true)
    private String[] authAppIds;

    @NacosValue(value = "${honorhome-apigateway.ignore.url:null}", autoRefreshed = true)
    private String[] ignoreUrlLists;

    @Autowired
    private TokenUtils tokenUtils;

    @Override
    public BmsBaseResponse userAuth(HttpServletRequest request) {
        if (request == null) {
            return BmsBaseResponse.error(ResponseEnum.BAD_REQUEST);
        }
        try {
            String appId = request.getHeader(HeaderConstant.HEADER_APP_ID);
            // 先验证appId
            if (StringUtils.isNotBlank(appId) && !checkAppId(appId)) {
                log.error("[appId match error,appId is {}]", appId);
                return BmsBaseResponse.error(ResponseEnum.AUTH_VERIFY_INVALID);
            }
            String token = request.getHeader(HeaderConstant.HEADER_TOKEN);
            String userId = request.getHeader(HeaderConstant.HEADER_USER_ID);
            // appid缺失或者验证不通过验证token
            if (StringUtils.isNotBlank(token) && StringUtils.isNotBlank(userId)) {
                return tokenUtils.tokenAuth(token, userId, Constants.BUSINESS_NAME);
            } else {
                // 验证url,未带用户信息同时不需要用户登录的直接跳过
                List<String> stringList = Arrays.asList(ignoreUrlLists);
                if (!stringList.isEmpty()) {
                    String uri = request.getRequestURI();
                    for (String ignoreUrl : stringList) {
                        if (uri.startsWith(ignoreUrl)) {
                            return BmsBaseResponse.OK;
                        }
                    }
                }
                log.error("[url filter error,url is {}]", request.getRequestURI());
                return BmsBaseResponse.error(ResponseEnum.AUTH_VERIFY_INVALID);
            }
        } catch (Exception e) {
            log.error("auth error", e);
            return BmsBaseResponse.error(ResponseEnum.API_GATEWAY_AUTH_ERROR);
        }
    }

    private boolean checkAppId(String appId) {
        List<String> authLists = Arrays.asList(authAppIds);
        if (!CollectionUtils.isEmpty(authLists)) {
            return authLists.contains(appId);
        }
        return false;
    }
}

标签:return,String,request,api,base,BmsBaseResponse,import,com,gateway
来源: https://www.cnblogs.com/kehuaihan/p/16524436.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有