日本熟妇hd丰满老熟妇,中文字幕一区二区三区在线不卡 ,亚洲成片在线观看,免费女同在线一区二区

HTTP任務簽名認證

更新時間:

為確保HTTP任務的服務接收方能安全地處理分布式任務調度平臺SchedulerX發起的調度請求,調度端會在HTTP請求頭中默認采用SHA1-RSA簽名算法生成schedulerx-signature字段簽名串,用于服務端做認證處理。本文介紹如何進行HTTP任務簽名認證。

簽名驗簽流程

1626857968216-b3e05058-8d62-4daa-9f1e-8b34da20e5ba..jpeg

驗證方案(JAVA)

您需要下載簽名證書來進行請求的簽名認證處理,具體驗證方法如下所示。

  1. 初始化構建AppKey與GroupId的映射配置,用于生成待簽數據。

  2. 獲取簽名時間戳進行有效時間校驗。例如,60秒內有效。

  3. 獲取簽名算法版本,校驗版本是否一致。

  4. 獲取待簽字符串,規則如下所示。

    METHOD + "\n"
    + HTTP-URL & QUERY-STRING + "\n"
    + APP-KEY + "\n"
    + COOKIE + "\n"
    + CanonicalizedSCXHeaders + "\n"
    + POST-BODY
    • METHOD:HTTP的請求方法。

    • HTTP-URL & QUERY-STRING:請求地址以及請求參數字符串。

    • APP-KEY:根據GroupID需要獲取對應的Appkey。

    • COOKIE:分布式任務調度平臺中配置的Cookie信息。

    • CanonicalizedSCXHeaders:HTTP請求頭中schedulerx-開頭的字段組合,按字符順序排列。

    • POST-BODY:針對POST請求攜帶的body內容。

    POST
    http://localhost:18080/hello?key=value
    AjS6+IQ4Czx/**********==
    cookie:
    schedulerx-attempt:0
    schedulerx-datatimestamp:1626851714550
    schedulerx-groupid:local.test
    schedulerx-jobid:12
    schedulerx-jobname:httptest
    schedulerx-maxattempt:0
    schedulerx-scheduletimestamp:1626851714550
    schedulerx-signature-method:SHA1withRSA
    schedulerx-signature-timestamp:1626851714555
    schedulerx-signature-version:1.0
    schedulerx-user:%E5%8D%83x%28330965%29
    test=test

    簽名驗證過濾器參考代碼如下所示。

    展開查看代碼

    public class SignatureVerificationFilter implements Filter {
    
        private final String HTTP_JOB_HEADER_PREFIX = "schedulerx-";
        
        private final String HTTP_SIGNATURE_VERSION = "1.0";
    
        private final Map<String, String> appKeyMap = new HashMap<>();
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            //TODO 此處需要自行根據對接的應用構建對接的應用AppKey列表
            appKeyMap.put("groupId", "APPKEY*******");
        }
    
        @Override
        public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
            try {
                // 可獲取schedulerx-signature-timestamp進行失效驗證
                Long signatureTimestamp = Long.parseLong(((HttpServletRequest) servletRequest).getHeader("schedulerx-signature-timestamp"));
                if(System.currentTimeMillis() - signatureTimestamp > 60*1000){
                    ((HttpServletResponse)servletResponse).sendError(HttpServletResponse.SC_UNAUTHORIZED, "簽名已超時.");
                    return;
                }
                
                // 判斷當前簽名驗證算法版本
                String signatureVersion = ((HttpServletRequest) servletRequest).getHeader("schedulerx-signature-version");
                if(!HTTP_SIGNATURE_VERSION.equals(signatureVersion)){
                    ((HttpServletResponse)servletResponse).sendError(HttpServletResponse.SC_UNAUTHORIZED, "簽名算法版本已變更.");
                    return;
                }
             	// 獲取待簽名數據
                String content = getSignContent((HttpServletRequest)servletRequest, "");
                
                // 獲取請求頭中簽名信息
                String signature = ((HttpServletRequest) servletRequest).getHeader("schedulerx-signature");
                
                // 獲取證書
                // 進行簽名驗證
                boolean res = verify("/Users/yaohui/certificate.crt", content, signature);
                System.out.println("驗證結果:"+res);
                if(res) {
                    filterChain.doFilter(servletRequest, servletResponse);
                }else {
                    ((HttpServletResponse)servletResponse).sendError(HttpServletResponse.SC_UNAUTHORIZED, "簽名驗證未通過.");
                }
            } catch (SignatureException e) {
                ((HttpServletResponse)servletResponse).sendError(HttpServletResponse.SC_UNAUTHORIZED, "簽名驗證異常:" + e.getMessage());
            }
        }
    
        /**
         * 對文本進行驗簽
         * @param publicKeyPath
         * @param message
         * @param signature
         * @return
         * @throws SignatureException
         */
        public static boolean verify(String publicKeyPath, String message, String signature) throws SignatureException{
            try {
                Signature sign = Signature.getInstance("SHA1withRSA");
                byte[] keyBytes = Files.readAllBytes(Paths.get(publicKeyPath));
                X509Certificate cert = X509Certificate.getInstance(keyBytes);
                PublicKey publicKey = cert.getPublicKey();
                sign.initVerify(publicKey);
                sign.update(message.getBytes("UTF-8"));
                return sign.verify(Base64.decodeBase64(signature.getBytes("UTF-8")));
            } catch (Exception ex) {
                throw new SignatureException(ex);
            }
        }
    
        /**
         * 獲取加簽內容信息
         * @param request
         * @param appKey
         * @return
         * @throws IOException
         */
        private String getSignContent(HttpServletRequest request, String appKey) throws IOException {
            StringBuilder sb = new StringBuilder();
            // 請求方式Method
            sb.append(request.getMethod());
            sb.append("\n");
            // http請求地址
            String fullUrl = request.getRequestURL()+ (StringUtils.isEmpty(request.getQueryString())?"":"?"+URLDecoder.decode(request.getQueryString(), "UTF-8"));
            sb.append(fullUrl);
            sb.append("\n");
            // 當前請求對應的AppKey
            sb.append(appKeyMap.get(request.getHeader("schedulerx-groupid")));
            sb.append("\n");
    		// cookie信息
            sb.append("cookie" + ":" + request.getHeader("cookie"));
            sb.append("\n");
    
            List<String> schedulerXHeaders = new ArrayList();
            //獲取請求頭信息
            Enumeration headerNames = request.getHeaderNames();
            //使用循環遍歷請求頭,并通過getHeader()方法獲取一個指定名稱的頭字段
            while (headerNames.hasMoreElements()){
                String headerName = (String) headerNames.nextElement();
                // 過濾簽名頭
                if (headerName.startsWith(HTTP_JOB_HEADER_PREFIX) && !"schedulerx-signature".equals(headerName)) {
                    schedulerXHeaders.add(headerName + ":" + request.getHeader(headerName));
                }
            }
            // 對SchedulerX相關的請求頭排序拼接
            Collections.sort(schedulerXHeaders);
            for (String kv : schedulerXHeaders) {
                sb.append(kv);
                sb.append("\n");
            }
            if (request.getMethod().equals("POST")) {
                // 對于POST將其請求內容作為加簽內容的一部分,對于該部分內容需要配套
                InputStream is = request.getInputStream();
                byte[] content = new byte[request.getContentLength()];
                is.read(content);
                ContentType contentType = ContentType.parse(request.getContentType());
                sb.append(new String(content, contentType.getCharset()));
            }
            return sb.toString();
        }
        
        @Override
        public void destroy() {}
    }
    說明

    CacheRequestInputStreamFilter用于對Request請求中的inputStream進行緩存處理,以便后續在針對POST請求驗簽時,獲取待簽數據內容。

    展開查看代碼

    @Order(Ordered.HIGHEST_PRECEDENCE)
    class CacheRequestInputStreamFilter implements Filter {
        
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {}
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            ContentCachingRequestWrapper requestToUse = new ContentCachingRequestWrapper((HttpServletRequest) request);
            chain.doFilter(requestToUse, response);
        }
        
        @Override
        public void destroy() {}
    
        static class ContentCachingRequestWrapper extends HttpServletRequestWrapper {
    
            private byte[] body;
    
            private BufferedReader reader;
    
            private ServletInputStream inputStream;
    
            ContentCachingRequestWrapper(HttpServletRequest request) throws IOException{
                super(request);
                InputStream is = request.getInputStream();
                body = new byte[request.getContentLength()];
                is.read(body);
                inputStream = new RequestCachingInputStream(body);
            }
    
            public byte[] getBody() {
                return body;
            }
    
            @Override
            public ServletInputStream getInputStream() throws IOException {
                if (inputStream != null) {
                    return inputStream;
                }
                return super.getInputStream();
            }
    
            @Override
            public BufferedReader getReader() throws IOException {
                if (reader == null) {
                    reader = new BufferedReader(new InputStreamReader(inputStream, getCharacterEncoding()));
                }
                return reader;
            }
    
            private static class RequestCachingInputStream extends ServletInputStream {
    
                private final ByteArrayInputStream inputStream;
    
                public RequestCachingInputStream(byte[] bytes) {
                    inputStream = new ByteArrayInputStream(bytes);
                }
                @Override
                public int read() throws IOException {
                    return inputStream.read();
                }
    
                @Override
                public boolean isFinished() {
                    return inputStream.available() == 0;
                }
    
                @Override
                public boolean isReady() {
                    return true;
                }
    
                @Override
                public void setReadListener(ReadListener readlistener) {}
    
            }
        }
    }