基于iuap平台组件创建加密签名api验证

一、加密签名api验证背景
最近一直在研究iuap平台的开发和使用,发现平台自带加签组件来支持创建api签名验证,但是demo不够完善,摸索了一下,写入博客和大家分享一下,在以后遇到使用iuap平台时,自己的应用需要用到发布api以后能做加密签名验证。此能力需要依赖iuap平台的组件包:iuap-security。
二、加密签名api验证实现
1.由于iuap平台的权限验证框架使用的是shiro框架,本次功能实现也基于shiro框架的过滤器进行实现。
2.创建shiro签名过滤器

public class SignAuthFilter extends AccessControlFilter {

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

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
        return false;
    }

    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        HttpServletResponse rp = (HttpServletResponse) response;
        rp.setCharacterEncoding("UTF-8");
        rp.setContentType("application/json;charset=UTF-8");
        if ((request instanceof HttpServletRequest)) {
            HttpServletRequest httpRequest = (HttpServletRequest) request;
            //从http头取签名信息,如果http头不存在,则从请求参数里取
            String sign = httpRequest.getHeader("sign");
            if (StringUtils.isEmpty(sign)) {
                sign = httpRequest.getParameter("sign");
            }
            //从http头取appId信息,如果http头不存在,则从请求参数里取
            String appId = httpRequest.getHeader("appid");
            if (StringUtils.isEmpty(appId)) {
                appId = httpRequest.getParameter("appid");
            }
            //判断签名信息和appId是否为空
            if ((null == sign) || (null == appId)) {
                rp.setStatus(400);
                rp.addHeader("Send event message validate error", "请求方法不允许,请检查参数!");
                rp.getWriter().write("sign请求方法不允许,请检查参数!");
                return false;
            }
            //验证签名时间
            String ts = httpRequest.getHeader("ts");
            if (StringUtils.isEmpty(ts)) {
                ts = httpRequest.getParameter("ts");
            }
            if (null == ts) {
                rp.setStatus(400);
                rp.addHeader("Send event message validate error", "请求方法不允许,请检查参数!");
                rp.getWriter().write("ts请求方法不允许,请检查参数!");
                return false;
            }

            if (StringUtils.isNumeric(ts)) {
                long sendTs = Long.parseLong(ts);
                //如果签名有效时间在有效期外,则提示签名过期(当前时间-签名有效时间大于5分钟,则认为签名有效时间过期)
                if (System.currentTimeMillis() - sendTs > 300000L) {
                    HttpServletResponse resp = (HttpServletResponse) response;
                    resp.setStatus(400);
                    resp.addHeader("send message validate error", " 400 ,签名已经过期!");
                    resp.getWriter().write("签名已经过期!");
                    return false;
                }
            }
            //验证签名信息
            if (!ValidatorSigna(sign, appId, httpRequest)) {
                rp.setStatus(400);
                rp.addHeader("Send event message validate error", "请求方法不允许,请检查参数!");
                rp.getWriter().write("key请求方法不允许,请检查参数!");
                return false;
            }

        }

        return true;
    }

    /**
      * 验证签名有效性
      * @param httpRequset
      * @return
     */
    private boolean ValidatorSigna(String sign, String appId, HttpServletRequest httpRequset) {

        if ((StringUtils.isNotEmpty(sign)) && (StringUtils.isNotEmpty(appId))) {
            try {
                //获取url全路径
                String url = httpRequset.getRequestURL().toString();
                //获取查询参数
                if (StringUtils.isNotBlank(httpRequset.getQueryString())) {
                    url = url + "?" + httpRequset.getQueryString();
                }
                //生成验签支撑对象
                SignProp prop = SignPropGenerator.genSignProp(url);
                return new VirifyFactory().getVerifier(appId).verify(sign, prop);
            } catch (UAPSecurityException e) {
                logger.error(e.getMessage(), e);
            } catch (MalformedURLException e) {
                logger.error(e.getMessage(), e);
            }
        }
        return false;
    }

    class VirifyFactory extends ServerVerifyFactory {
        @Override
        protected Credential genCredential(String appId) {
            try {
                return ClientCredentialGenerator.loadCredential(VirifyFactory.class.getResource("/").getFile().toString() + "/security/authfile.txt");
            } catch (UAPSecurityException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

3.修改applicationContext-shiro.xml配置文件,对api进行权限过滤
3.1增加过滤器

>
	>

3.2加入过滤器集合
基于iuap平台组件创建加密签名api验证_第1张图片
3.3增加过滤URL
基于iuap平台组件创建加密签名api验证_第2张图片
到此整个扩展就完成了,下面我们进行测试代码的编写,为了让应用中使用更加的边接,做了一个工具类进行调用。
4.api工具类

public class ApiUtils {

    /**
      * api调用
      * @param apiUrl   api地址
      * @param apiParams    api参数
     */
    public static void ApiCall(String apiUrl, ApiParams apiParams, String apiType) {
        Map<String, String> headers = new LinkedHashMap<String, String>();
        //传出http请求参数,http请求参数一定要在生成sign之前传入,否则在生成sign时会和服务器的不一样。
        headers.put("ts", apiParams.getExpiredTs());

        headers.put("sign", geneClientSign(apiUrl, apiParams));
        headers.put("appid", apiParams.getAppId());
        //如果是post请求,则用post
        if ("post".equals(apiType)) {
            //如果body参数为空,则使用http参数发起请求,否则使用body参数
            if ("".equals(apiParams.getBodyParams())) {
                HttpUtils.postUrl(apiUrl, apiParams.getHttpParams(), headers, "UTF-8");
            } else {
                HttpUtils.postUrl(apiUrl, apiParams.getBodyParams(), headers, "UTF-8");
            }
        } else {
            HttpUtils.doGet(apiUrl, apiParams.getHttpParams(), headers, "UTF-8");
        }

    }

    /**
      * 生成客户端签名
      * @param apiUrl   api地址
      * @param apiParams    api参数
      * @return 加密签名字符串
     */
    private static String geneClientSign(String apiUrl, ApiParams apiParams) {
        //解析http参数重新生成url地址
        try {
            Map<String, String> params = apiParams.getHttpParams();
            if ((params != null) && (!params.isEmpty())) {
                List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    String value = entry.getValue();
                    if (value != null) {
                        pairs.add(new BasicNameValuePair(entry.getKey(), value));
                    }
                }
                apiUrl = apiUrl + "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, "UTF-8"));
            }
            //根据新的url地址生成验签支撑对象
            SignProp prop = SignPropGenerator.genSignProp(apiUrl);
            prop.setIp(apiParams.getServerIp());

            Credential credential = new Credential();
            credential.setAppId(apiParams.getAppId());
            credential.setKey(apiParams.getSignKey());
            credential.setExpiredTs(apiParams.getExpiredTs());
            DigestSigner digestSigner = new DigestSigner(credential);
            return digestSigner.sign(prop);
        } catch (UAPSecurityException | ParseException | IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

5.junit测试

public class MaCrUserApiTest extends AbstractJUnit4SpringContextTests {

    /**
      * 创建加签文件
      *
     */
    @Test
    public void apiCreateSigleFile() {
        byte[] appidByte = new String("OA移动端").getBytes();
        String appid = IUAPESAPI.encoder().encodeForBase64(appidByte);

        try {
            String key = IUAPESAPI.encryptor().encrypt(appid);
            SimpleDateFormat smdf = new SimpleDateFormat("yyyy-MM-dd");
            Long overdueDateTime = smdf.parse("2019-12-06").getTime();

            File file = new File("D:\\oamobile.txt");

            FileWriter fw = new FileWriter(file);
            BufferedWriter write = new BufferedWriter(fw);

            write.write("appid=" + appid);
            write.newLine();//换行
            write.write("key=" + key);
            write.newLine();//换行
            write.write("expiredTs=" + overdueDateTime);
            write.flush();
            write.close();
        } catch (EncryptException | ParseException | IOException e) {
            e.printStackTrace();
        }

    }

    @Test
    public void apiGetCall() throws ParseException {
        ApiParams apiParams = new ApiParams();
        apiParams.setAppId("5YWo5Z+f5Lit5Y+w");
        Long overdueDateTime = System.currentTimeMillis();
        apiParams.setExpiredTs(overdueDateTime.toString());
        apiParams
                .setSignKey("ETMsDgAAAXB8GP61ABRBRVMvQ0JDL1BLQ1M1UGFkZGluZwCAABAAEHGgER1sydlUQsEWeOfkHMQAAAAgvJqoL8hcvxYm3J/h7VXPR+FYE95qmsUDHm1gvbLx+TsAFEtMmFVE7aKNyxlu37VlrxI9sTHl");

        Map<String, String> httpParams = new LinkedHashMap<String, String>();
        httpParams.put("indocno", "40281181662e4ecb01662e4ecdab0000");

        apiParams.setHttpParams(httpParams);
        ApiUtils.ApiCall("http://localhost:8081/appcloud-main/api/macruserweb/findbyid", apiParams, null);
    }

    @Test
    public void apiPostCall() throws ParseException {
        Properties properties = PropertiesUtils.getProperties("/security/authfile.txt");
        ApiParams apiParams = new ApiParams();
        apiParams.setAppId(properties.getProperty("appid"));
        Long overdueDateTime = System.currentTimeMillis();
        apiParams.setExpiredTs(overdueDateTime.toString());
        apiParams.setSignKey(properties.getProperty("key"));

        List<MaLgBusLog> maLgBusLogList = new ArrayList<MaLgBusLog>();

        MaLgBusLog maLgBusLog = new MaLgBusLog();
        maLgBusLog.setIpAddress("asdfasdfas");
        maLgBusLog.setRequestUrl("asdfasdfas");
        maLgBusLog.setRequestMethod("asdfasdfas");
        maLgBusLog.setRequestParam("你好安抚大使的");
        maLgBusLog.setRecTime(new Date());

        maLgBusLogList.add(maLgBusLog);

        ObjectMapper objectMapper = new ObjectMapper();
        try {
            String json = objectMapper.writeValueAsString(maLgBusLogList);
            apiParams.setBodyParams(json.toString());
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        //JSONArray json = JSONArray.fromObject(maLgBusLogList);

        ApiUtils.ApiCall("http://localhost:8181/appcloud-log/api/malgbuslogweb/savedata", apiParams, "post");
    }
}

至此基于iuap平台组件创建加密签名api验证就已经全部完成!

你可能感兴趣的:(Java,过滤器,java,post)