需求分析
在互联中,我们的服务是不对外开放的,但是有先场景下我们可以对外开放,但是必须是系统所允许的用户才可以,这样做一方面保证安全,另一方面可以提升平台的能力,比如调用微信的接口必须要进行微信开发者认证,比如阿里云等等,那么我们如何实现一个自己的开放平台呢?
实现思路
平台接入流程图如下:
提供一个申请接入的入口,用户通过注册审核通过后获取appid和appserect得到访问应用服务的钥匙,然后通过钥匙获取访问的token.
服务端验证流程图如下
服务端要验证访问者是不是真实的用户,有时候还可以增加ip白名单进行拦截,具体要根据业务进行扩展,总体思路如上,返回token后,用户就可以拿着token调用服务的API,服务端可以通过aop进行接口统计等等。
服务端验证代码示例
/*** 获取登录token** @param body* @param request* @return*/public String getAccessToken(String body, HttpServletRequest request) {log.info("body是:{}", body);String appid = request.getHeader("appid");
// String secret1 = request.getHeader("secret");try {if (!StringUtils.hasText(body)) {throw new ServiceException("必传参数:body不能为空!");}UserApplicationEntity validAppidAndSecret = this.isValidAppidAndSecret(appid);if (validAppidAndSecret==null) {throw new ServiceException("appid/secret:验证失败");}String secret1 = validAppidAndSecret.getSecret();
// String decode = URLDecoder.decode(body, StandardCharsets.UTF_8);log.info("解密后的值是:{}", body);String decryptBodyStr = RsaUtil.decryptStr(body, secret1);log.info("P{}",decryptBodyStr);JSONObject decryptBody = JSONObject.parseObject(decryptBodyStr);String secret = decryptBody.getString("secret");//验证appid和secret合法性if(!secret1.equals(secret)){throw new ServiceException("secret:验证失败,请联系管理员");}Date expiryDate = validAppidAndSecret.getExpiryDate();int compare = DateUtil.compare(expiryDate, new Date());if(compare<0){throw new ServiceException("appid/secret:已过期,请联系管理员");}//根据当前时间戳和请求时间戳验证是否盗链Long timestamp = decryptBody.getLong("timestamp");long requestInterval = System.currentTimeMillis() - timestamp;if (requestInterval > REQUEST_EXPIRES_TIME) {throw new ServiceException("时间已经超时");}//验证调用方身份合法性(验证签名)Optional<String> signOpt = Optional.ofNullable(request.getHeader("sign"));if (signOpt.isEmpty()) {throw new ServiceException("身份不合法!");}String grantType = decryptBody.getString("grantType");String salt = decryptBody.getString("salt");String generatedSign = SecureUtil.md5(appid + secret + grantType + timestamp+salt);String sign = signOpt.get();if (!sign.equals(generatedSign)) {throw new ServiceException("身份不合法!");}//通过jwt生成access tokenMap<String, Object> payload = new HashMap<>();payload.put("appid", appid);payload.put("secret", secret);payload.put("grantType", grantType);payload.put("timestamp", timestamp);payload.put("salt", salt);payload.put("sign", sign);return jwtService.generateAccessToken(appid,payload);} catch (Exception e) {log.error("验证失败,请联系管理员:{}" , e);throw new ServiceException("验证失败,请联系管理员:" + e);}}