课程概要:
API网关是一个轻量的 java http 接口组件,可以无缝的将普通的 Serive 方法转换成 http 接口,并从以下几点来达到提高开发效率与保证接口质量的目的。
1.去掉mvc控制器,将http请求直接无缝接入Java 服务接口
2.统一出/入参格式
3.统一异常规范
4.自动检测服务接口规范
请求参数:
String method; // f方法名称
json parameter; // 业务参数
long timestamp; // 请求时间戳
实现技术:
1.java servlet
2.spring IOC
3.Json 转换工具的使用
1.白名单组
无需登录认证,无需鉴权,如网站首页
2.黑名单组
和用户私密信息(userId)相关的,需进行安全认证的接口,如提交订单,操作与用户ID相关的功能
通常开放平台,默认是 Autho 2.0 协议标准实现
3.黑白名单组
根据需求设置认证,展示的结果不一样,如商品详情页,如果有登录,则显示和用户相关的信息如评论、收藏、会员价格等
1.登陆鉴权
Token 可以识别用户登录是否登录,在 PC端开发时,直接使用一个token,然后存放至cookie里面;
2.防止业务参数篡改
确保请求的业务参数不被修改
3.保护用户敏感信息
UserId、 密码 , 不使用明文在网络直接传输,使用token 代替
4.防签名伪造
token签名后,要防止token签名被伪造,否则相当于API直接暴露给不法分子,网站处于裸奔状态
一是要防止单个用户的伪造,另一个是要防止大规模的伪造
整体架构分为Token生成与认证两部分:
Token生成指在登陆成功之后生成 Token 和密钥,并其与用户隐私信息、客户端信息一起存储至Token表,同时返回Token 与Secret 至客户端。
签名规则:
1.已指定顺序拼接字符串 secret+method+param+token+timestamp+secret
2.使用MD5进行加密,在转化成大写
签名的目的:
1.防篡改
因为param参数在一开始就被进行MD5签名了,若param被修改的话,这时候生成的签名和客户端的签名值肯定是不一致的
2.防伪造
Secret 是被放在客户端里面的,如果请求中路由被拦截(除非用HTTPS协议),此时请求可能被伪造,但是拿不到secret 的话,是生成不了正确的签名的
3.防重复使用签名
基于时间戳实现,允许与服务端10分钟误差
主要包括两个流程:
1、Token生成
登录成功后插,生成token与secret 保存至数据库
2、Token 认证相关解决方案:
1.接口如何标识黑白名单?
使用一个是否需要登录的标志的来区分:
@Target({ ElementType.METHOD})
@Retention(RententionPolicy.RUNTIME)
Public @interface APIMapping {
// String value();
boolean userLogin = false; // 默认为白名单
}
// 使用
@APIMapping(userLogin = true)
2.签名具体验证流程?
private ApiRequest signCheck(ApiRequest request) throws ApiException {
Token token = tokenService.getToken(request.getAccessToken());
if (token == null) {
throw new ApiException("验证失败:指定'Token'不存在");
}
if (token.getExpiresTime().before(new Date())) {
throw new ApiException("验证失败:指定'Token'已失效");
}
// 生成签名
String methodName = request.getMethodName();
String accessToken = token.getAccessToken();
String secret = token.getSecret();
String params = request.getParams();
String timestamp = request.getTimestamp();
String sign = Md5Util.MD5(secret + methodName + params + token + timestamp + secret);
if (!sign.toUpperCase().equals(request.getSign())) {
throw new ApiException("验证失败:签名非法");
}
// 时间验证
if (Math.abs(Long.valueOf(timestamp) - System.currentTimeMillis()) > 10 * 60 * 1000) {
throw new ApiException("验证失败:签名失效");
}
request.setLogin(true);
request.setMemberId(token.getMemberId());
return request;
}
3.用户ID等信息如何传递给业务实现接口?
1) 一般方法
// 将UserId存储在ThreadLocal里面,通过 context 获取
Context.getInstallcell().getUserId();
2) HttpRequest request;
3) 借鉴HttpRequest 封装一个 APIRequest
private String userId; // 用户ID
private String accessToken; // Token
private String sign; // 签名
private String eCode; // 设备码
private String timestamp; // 时间戳
private String clientIp; // 客户端IP
private boolean isLogin; // 是否登录
private String params; // 业务参数
...