互联网并发与安全系列教程(09) -基于AccessToken方式实现API设计

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 互联网并发与安全系列教程(09) -基于AccessToken方式实现API设计

现在有一个需求:A公司与B公司进行合作,B公司需要调用A公司开放的外网接口获取数据,

如何保证外网开放接口的安全性?

常用解决办法:

  1. 使用令牌方式
  2. 使用加签名方式,防止篡改数据
  3. 使用Https加密传输
  4. 搭建OAuth2.0认证授权
  5. 搭建网关实现黑名单和白名单

下面来讲解使用令牌的方式搭建API开放平台:

基于AccessToken方式实现API设计

原理:为每个合作机构创建对应的appid、app_secret,生成对应的access_token(有效期2小时),在调用外网开放接口的时候,必须传递有效的access_token。简单的说就是我们平时开发中说的“授权”(“授权”这个东西涉及到收费的问题,坑~)。

数据库表设计:

SQL DDML:

CREATE TABLE `m_app` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `app_name` varchar(255) DEFAULT NULL,
  `app_id` varchar(255) DEFAULT NULL,
  `app_secret` varchar(255) DEFAULT NULL,
  `is_flag` varchar(255) DEFAULT NULL,
  `access_token` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
字段描述:
字段名 解析
App_Name 表示机构名称
App_ID 应用id
App_Secret 应用密钥 (可更改)
Is_flag 是否可用 (是否对某个机构开放)
access_token 上一次access_token
代码

获取AccessToken:

// 创建获取getAccessToken
@RestController
@RequestMapping(value = "/auth")
public class AuthController extends BaseApiService {
  @Autowired
  private BaseRedisService baseRedisService;
  private long timeToken = 60 * 60 * 2;
  @Autowired
  private AppMapper appMapper;
  // 使用appId+appSecret 生成AccessToke
  @RequestMapping("/getAccessToken")
  public ResponseBase getAccessToken(AppEntity appEntity) {
    AppEntity appResult = appMapper.findApp(appEntity);
    if (appResult == null) {
      return setResultError("没有对应机构的认证信息");
    }
    int isFlag = appResult.getIsFlag();
    if (isFlag == 1) {
      return setResultError("您现在没有权限生成对应的AccessToken");
    }
    // ### 获取新的accessToken 之前删除之前老的accessToken
    // 从redis中删除之前的accessToken
    String accessToken = appResult.getAccessToken();
    baseRedisService.delKey(accessToken);
    // 生成的新的accessToken
    String newAccessToken = newAccessToken(appResult.getAppId());
    JSONObject jsonObject = new JSONObject();
    jsonObject.put("accessToken", newAccessToken);
    return setResultSuccessData(jsonObject);
  }
  private String newAccessToken(String appId) {
    // 使用appid+appsecret 生成对应的AccessToken 保存两个小时
    String accessToken = TokenUtils.getAccessToken();
    // 保证在同一个事物redis 事物中
    // 生成最新的token key为accessToken value 为 appid
    baseRedisService.setString(accessToken, appId, timeToken);
    // 表中保存当前accessToken
    appMapper.updateAccessToken(accessToken, appId);
    return accessToken;
  }
}

编写拦截器拦截请求,验证AccessToken:

//验证AccessToken 是否正确
@Component
public class AccessTokenInterceptor extends BaseApiService implements HandlerInterceptor {
  @Autowired
  private BaseRedisService baseRedisService;
  /**
   * 进入controller层之前拦截请求
   * 
   * @param httpServletRequest
   * @param httpServletResponse
   * @param o
   * @return
   * @throws Exception
   */
  public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o)
      throws Exception {
    System.out.println("---------------------开始进入请求地址拦截----------------------------");
    String accessToken = httpServletRequest.getParameter("accessToken");
    // 判断accessToken是否空
    if (StringUtils.isEmpty(accessToken)) {
      // 参数Token accessToken
      resultError(" this is parameter accessToken null ", httpServletResponse);
      return false;
    }
    String appId = (String) baseRedisService.getString(accessToken);
    if (StringUtils.isEmpty(appId)) {
      // accessToken 已经失效!
      resultError(" this is  accessToken Invalid ", httpServletResponse);
      return false;
    }
    // 正常执行业务逻辑...
    return true;
  }
  public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o,
      ModelAndView modelAndView) throws Exception {
    System.out.println("--------------处理请求完成后视图渲染之前的处理操作---------------");
  }
  public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
      Object o, Exception e) throws Exception {
    System.out.println("---------------视图渲染之后的操作-------------------------0");
  }
  // 返回错误提示
  public void resultError(String errorMsg, HttpServletResponse httpServletResponse) throws IOException {
    PrintWriter printWriter = httpServletResponse.getWriter();
    printWriter.write(new JSONObject().toJSONString(setResultError(errorMsg)));
  }
}


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
9天前
|
API
车牌号归属地查询免费API接口教程
本接口用于根据车牌号查询社会车辆的归属地,不支持军车、使馆等特殊车牌。请求地址为 `https://cn.apihz.cn/api/other/chepai.php`,支持 POST 和 GET 请求。请求参数包括 `id`、`key` 和 `words`,返回数据包含车牌归属地信息。示例请求:`https://cn.apihz.cn/api/other/chepai.php?id=88888888&key=88888888&words=川B1234`。
43 21
|
7天前
|
API
获取网页重定向地址免费API接口教程
该API用于获取网页重定向跳转后的最终地址。请求地址为`https://cn.apihz.cn/api/wangzhan/tiaozhuan.php`,支持POST或GET方式。请求参数包括`id`、`key`和`url`,返回数据包含状态码`code`和最终URL`url`。示例返回:`{"code":200,"url":"https://www.baidu.com/"}`。
48 29
|
8天前
|
网络协议 API
检测指定TCP端口开放状态免费API接口教程
该API用于检测目标主机指定TCP端口是否开放,适用于检测连通状态等场景。支持指定大陆、美国、香港等检测节点。请求地址为 `https://cn.apihz.cn/api/wangzhan/port.php`,支持POST和GET请求方式。请求参数包括 `id`、`key`、`type`、`host` 和 `port`。返回参数包含检测结果和状态码。示例请求:`https://cn.apihz.cn/api/wangzhan/port.php?id=88888888&key=88888888&type=1&host=49.234.56.78&port=80`。
|
7天前
|
API 数据安全/隐私保护
抖音视频,图集无水印直链解析免费API接口教程
该接口用于解析抖音视频和图集的无水印直链地址。请求地址为 `https://cn.apihz.cn/api/fun/douyin.php`,支持POST或GET请求。请求参数包括用户ID、用户KEY和视频或图集地址。返回参数包括状态码、信息提示、作者昵称、标题、视频地址、封面、图集和类型。示例请求和返回数据详见文档。
|
10天前
|
前端开发 JavaScript API
取网页纯文本内容免费API接口教程
该API用于获取指定网页的纯文本内容,去除HTML标签、CSS和JS等元素。支持POST和GET请求,需提供ID、Key、URL等参数。请求示例:https://cn.apihz.cn/api/wangzhan/getyuan.php?id=88888888&key=88888888&url=www.apihz.cn&dy=1。返回纯文本数据。
|
7天前
|
JSON API 数据格式
淘宝 / 天猫官方商品 / 订单订单 API 接口丨商品上传接口对接步骤
要对接淘宝/天猫官方商品或订单API,需先注册淘宝开放平台账号,创建应用获取App Key和App Secret。之后,详细阅读API文档,了解接口功能及权限要求,编写认证、构建请求、发送请求和处理响应的代码。最后,在沙箱环境中测试与调试,确保API调用的正确性和稳定性。
|
19天前
|
供应链 数据挖掘 API
电商API接口介绍——sku接口概述
商品SKU(Stock Keeping Unit)接口是电商API接口中的一种,专门用于获取商品的SKU信息。SKU是库存量单位,用于区分同一商品的不同规格、颜色、尺寸等属性。通过商品SKU接口,开发者可以获取商品的SKU列表、SKU属性、库存数量等详细信息。
|
20天前
|
JSON API 数据格式
店铺所有商品列表接口json数据格式示例(API接口)
当然,以下是一个示例的JSON数据格式,用于表示一个店铺所有商品列表的API接口响应
|
30天前
|
编解码 监控 API
直播源怎么调用api接口
调用直播源的API接口涉及开通服务、添加域名、获取API密钥、调用API接口、生成推流和拉流地址、配置直播源、开始直播、监控管理及停止直播等步骤。不同云服务平台的具体操作略有差异,但整体流程简单易懂。
|
10天前
|
JSON API 数据安全/隐私保护
拍立淘按图搜索API接口返回数据的JSON格式示例
拍立淘按图搜索API接口允许用户通过上传图片来搜索相似的商品,该接口返回的通常是一个JSON格式的响应,其中包含了与上传图片相似的商品信息。以下是一个基于淘宝平台的拍立淘按图搜索API接口返回数据的JSON格式示例,同时提供对其关键字段的解释