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

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容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数据库实现在线游戏中的游戏玩家积分排行榜功能。
目录
相关文章
|
2月前
|
JSON 监控 API
在线网络PING接口检测服务器连通状态免费API教程
接口盒子提供免费PING检测API,可测试域名或IP的连通性与响应速度,支持指定地域节点,适用于服务器运维和网络监控。
|
2月前
|
JSON API PHP
通用图片搜索API:百度源免费接口教程
本文介绍一款基于百度图片搜索的免费API接口,由接口盒子提供。支持关键词搜索,具备详细请求与返回参数说明,并提供PHP及Python调用示例。开发者可快速集成实现图片搜索功能,适用于内容聚合、素材库建设等场景。
|
2月前
|
JSON 机器人 API
随机昵称网名API接口教程:轻松获取百万创意昵称库
接口盒子提供随机昵称网名API,拥有百万级中文昵称库,支持聊天机器人、游戏角色等场景的昵称生成。提供详细调用指南及多语言示例代码,助力开发者高效集成。
|
2月前
|
JSON API PHP
天气预报免费API接口【地址查询版】使用教程
本文介绍了如何使用中国气象局官方数据提供的免费天气预报API接口,通过省份和地点查询指定地区当日天气信息。该接口由接口盒子支持,提供JSON格式数据、GET/POST请求方式,并需注册获取用户ID和KEY进行身份验证。
1412 2
|
2月前
|
存储 JSON API
文本存储免费API接口教程
接口盒子提供免费文本存储服务,支持1000条记录,每条最多5000字符,适用于公告、日志、配置等场景,支持修改与读取。
|
2月前
|
数据采集 JSON 监控
获取网页状态码(可指定地域)免费API接口教程
本文介绍如何使用接口盒子的免费API获取网页状态码,支持国内、香港、美国等不同地域访问节点。内容包括接口参数、调用方法及示例,适用于网站监控、链接检查等场景。
|
2月前
|
JSON 物联网 API
天气预报免费API接口【IP查询版】使用教程
IP查询天气API是一款免费实用的接口,可根据IP地址自动获取所在地天气预报,支持自定义IP查询。核心功能包括自动识别请求IP、全国IP天气查询,数据源自中国气象局,无日调用上限。提供详细的返回参数及多语言示例代码,适用于网站、APP、物联网设备等应用场景。
|
22天前
|
JSON API 数据格式
淘宝/天猫图片搜索API接口,json返回数据。
淘宝/天猫平台虽未开放直接的图片搜索API,但可通过阿里妈妈淘宝联盟或天猫开放平台接口实现类似功能。本文提供基于淘宝联盟的图片关联商品搜索Curl示例及JSON响应说明,适用于已获权限的开发者。如需更高精度搜索,可选用阿里云视觉智能API。
|
20天前
|
JSON API 数据安全/隐私保护
深度分析淘宝卖家订单详情API接口,用json返回数据
淘宝卖家订单详情API(taobao.trade.fullinfo.get)是淘宝开放平台提供的重要接口,用于获取单个订单的完整信息,包括订单状态、买家信息、商品明细、支付与物流信息等,支撑订单管理、ERP对接及售后处理。需通过appkey、appsecret和session认证,并遵守调用频率与数据权限限制。本文详解其使用方法并附Python调用示例。
|
25天前
|
监控 算法 API
电商API接口对接实录:淘宝优惠券接口对接处理促销监控系统
在电商开发中,淘宝详情页的“券后价计算”是极易出错的环节。本文作者结合实战经验,分享了因忽略满减券门槛、有效期、适用范围等导致的踩坑经历,并提供了完整的解决方案,包括淘宝API签名生成、券后价计算逻辑、常见坑点及优化建议,助力开发者精准实现券后价功能,避免业务损失。