网站开发的目的意义,网站平台开发多少钱,做阿里网站卖东西赚钱,镇平县两学一做网站❤ 作者主页#xff1a;李奕赫揍小邰的博客 ❀ 个人介绍#xff1a;大家好#xff0c;我是李奕赫#xff01;(#xffe3;▽#xffe3;)~* #x1f34a; 记得点赞、收藏、评论⭐️⭐️⭐️ #x1f4e3; 认真学习!!!#x1f389;#x1f389; 文章目录 为什么需要AP… ❤ 作者主页李奕赫揍小邰的博客 ❀ 个人介绍大家好我是李奕赫(▽)~* 记得点赞、收藏、评论⭐️⭐️⭐️ 认真学习!!! 文章目录 为什么需要API签字认证API签名认证需要的参数API签名认证实现1.用户注册创建aksk2.加密算法3.发送调用接口请求4.验证签名是否正确 总结如何改善开发 最近在做一个API开放平台因为开发者可以上传接口到这个平台上面然后用户可以浏览平台进行付费次数调用。但值得思考的是如果用户量很大或者攻击者疯狂请求这个接口这会导致安全问题同时也会耗尽服务器性能影响正常用户的使用。 因此需要进行保护措施所以我使用的API签名认证进行权限认证。 为什么需要API签字认证 为了保证安全性不能让任何人都能调用接口。那么我们如何在后端实现签名认证呢我们需要两个东西即 accessKey 和 secretKey。这和用户名和密码类似不过每次调用接口都需要带上实现无状态的请求。这样即使你之前没来过只要这次的状态正确你就可以调用接口。所以我们需要这两个东西来标识用户。 他的本质就是签发签名使用签名。同时需要运用到加密算法对ak,sk加密成签名。 API签名认证需要的参数
参数 1accessKey调用的标识 复杂、无序、无规律 参数 2secretKey密钥复杂、无序、无规律 参数 3用户请求参数 参数 4sign加密的算法 参数 5加 nonce 随机数只能用一次。服务端要保存用过的随机数防止重放请求 参数 6加 timestamp 时间戳校验时间戳是否过期。防止重放请求。 防止重放作用 每个请求在发送时携带一个时间戳后端会验证该时间戳是否在指定的时间范围内例如不超过10分钟或5分钟。这可以防止对方使用昨天的请求在今天进行重放。通过这种方式我们可以一定程度上控制随机数的过期时间。因为后端需要同时验证这两个参数只要时间戳过期或随机数被使用过后端会拒绝该请求。因此时间戳可以在一定程度上减轻后端保存随机数的负担。通常情况下这两种方法可以相互配合使用。 API签名认证实现 1.用户注册创建aksk 1.每个用户在注册的时候就需要创建ak,sk
/**
* 盐值混淆密码
*/
private static final String SALT 123;
public long userRegister(String userAccount, String userPassword, String checkPassword) {// 1. 校验if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)) {throw new BusinessException(ErrorCode.PARAMS_ERROR, 参数为空);}if (userAccount.length() 4) {throw new BusinessException(ErrorCode.PARAMS_ERROR, 用户账号过短);}if (userPassword.length() 8 || checkPassword.length() 8) {throw new BusinessException(ErrorCode.PARAMS_ERROR, 用户密码过短);}// 密码和校验密码相同if (!userPassword.equals(checkPassword)) {throw new BusinessException(ErrorCode.PARAMS_ERROR, 两次输入的密码不一致);}synchronized (userAccount.intern()) {// 账户不能重复QueryWrapperUser queryWrapper new QueryWrapper();queryWrapper.eq(userAccount, userAccount);long count userMapper.selectCount(queryWrapper);if (count 0) {throw new BusinessException(ErrorCode.PARAMS_ERROR, 账号重复);}// 2. 加密String encryptPassword DigestUtils.md5DigestAsHex((SALT userPassword).getBytes());//3.分配accessKey,secretKey//使用DigestUtil.md5Hex将盐值、用户账户和5或8位随机数进行MD5加密String accessKey DigestUtil.md5Hex(SALTuserAccount RandomUtil.randomNumbers(5));String secretKey DigestUtil.md5Hex(SALTuserAccount RandomUtil.randomNumbers(8));// 4. 插入数据User user new User();user.setUserAccount(userAccount);user.setUserPassword(encryptPassword);user.setAccessKey(accessKey);user.setSecretKey(secretKey);boolean saveResult this.save(user);if (!saveResult) {throw new BusinessException(ErrorCode.SYSTEM_ERROR, 注册失败数据库错误);}return user.getId();}}在我们注册之中首先使用MD5对密码进行盐值加密。之后就是生成用户专属的aksk。利用DigestUtil加密算法将盐值用户账号随机数进行MD5加密生成这样就能生成用户专属的签名。
2.加密算法 加密算法种类相当多。对称加密、非对称加密、md5 签名不可解密等等。我们在这里使用的是SHA256算法的Digester。当然使用其他的算法都是可以的因为到时候验证签名的时候只需要再加密一边得到的ak1,sk1和库里面加密后的ak,sk一样即代表着验证成功
public class SignUtils {/*** 生成签名* param body* param secretKey 密钥* return 生成的签名字符串*/public static String genSign(String body, String secretKey) {// 使用SHA256算法的DigesterDigester md5 new Digester(DigestAlgorithm.SHA256);// 构建签名内容将哈希映射转换为字符串并拼接密钥String content body . secretKey;// 计算签名的摘要并返回摘要的十六进制表示形式return md5.digestHex(content);}
}将加密算法写成一个公共类用的时候直接调用即可。 3.发送调用接口请求
当用户调用接口时就应该将ak,sk以及timestamp时间戳加到请求头之中。使用加密算法生成签名。最后发送请求。
// 获取当前登录用户的ak和sk这样相当于用户自己的这个身份去调用
// 也不会担心它刷接口因为知道是谁刷了这个接口会比较安全
User loginUser userService.getLoginUser(request);
String accessKey loginUser.getAccessKey();
String secretKey loginUser.getSecretKey();
JjlApiClient jjlApiClient new JjlApiClient(accessKey, secretKey);
//添加请求头
private MapString, String getHeaders(String body, JjlApiClient jjlApiClient) {MapString, String hashMap new HashMap(4);hashMap.put(accessKey, jjlApiClient.getAccessKey());String encodedBody SecureUtil.md5(body);hashMap.put(body, encodedBody);hashMap.put(timestamp, String.valueOf(System.currentTimeMillis() / 1000));hashMap.put(sign, SignUtils.genSign(encodedBody, jjlApiClient.getSecretKey()));return hashMap;}4.验证签名是否正确 因为请求接口的链接不同做验证比较麻烦的话我们可以写一个网关将所有请求进行拦截。统一验证之后再调用接口。这个之后篇章在实现。本文主要是介绍API签字认证功能。
// 首先从请求头中获取参数
HttpHeaders headers request.getHeaders();
String accessKey headers.getFirst(accessKey);
String nonce headers.getFirst(nonce);
String timestamp headers.getFirst(timestamp);
String sign headers.getFirst(sign);
String body headers.getFirst(body);
/获取当前用户
User invokeUser null;
try{invokeUser innerUserService.getInvokeUser(accessKey);
}catch (Exception e){log.error(getInvokeUser error,e);
}
if(invokeUser null){return handleNoAuth(response);
}
// 直接校验如果随机数大于1万则抛出异常并提示无权限
if (Long.parseLong(nonce) 10000) {return handleNoAuth(response);
}
// 时间和当前时间不能超过5分钟
// 首先,获取当前时间的时间戳,以秒为单位
Long currentTime System.currentTimeMillis() / 1000;
final Long FIVE_MINUTES 60 * 5L;
if ((currentTime - Long.parseLong(timestamp)) FIVE_MINUTES) {return handleNoAuth(response);
}
//从库中查询出sk,然后利用加密算法得出签名两者一直则代表验证完成
String secretKey invokeUser.getSecretKey();
String serverSign SignUtils.genSign(body,secretKey);
if (sign null || !sign.equals(serverSign)) {return handleNoAuth(response);
}
验证完之后就可以调用接口。返回接口值。 总结如何改善开发 作为开发者每次调用接口都需要处理这一堆繁琐的事情这确实有些麻烦需要自己生成时间戳编写签名算法生成随机数等等这些都是相当繁琐的工作。因此构建接口开放平台时需要想办法让开发者能够以最简单的方式调用接口。开发者只需要关心传递哪些参数以及他们的密钥、APP等信息。一旦告诉了他们这些信息他们就可以轻松地进行调用了。 对于具体的随机数生成和签名生成过程开发者有必要关心吗显然是不需要的。因此我们需要为开发者提供一个易于使用的 SDK使其能够便捷地调用接口。因此接下来会发布文章来教大家怎么开发SDK