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

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Redis 版,经济版 1GB 1个月
简介: 互联网并发与安全系列教程(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
目录
相关文章
|
5天前
|
监控 安全 Java
java中并发Queue种类与各自API特点
java中并发Queue种类与各自API特点
18 0
|
9天前
|
XML 安全 API
API攻防-接口安全&SOAP&OpenAPI&RESTful&分类特征导入&项目联动检测
API攻防-接口安全&SOAP&OpenAPI&RESTful&分类特征导入&项目联动检测
|
9天前
|
Kubernetes 安全 Cloud Native
云上攻防-云原生篇&Kubernetes&K8s安全&API&Kubelet未授权访问&容器执行
云上攻防-云原生篇&Kubernetes&K8s安全&API&Kubelet未授权访问&容器执行
|
13天前
|
监控 安全 测试技术
确保第三方API安全的5个最佳实践
确保第三方API安全的5个最佳实践
|
16天前
|
Java 大数据 API
【大数据】HDFS、HBase操作教程(含指令和JAVA API)
【大数据】HDFS、HBase操作教程(含指令和JAVA API)
56 0
【大数据】HDFS、HBase操作教程(含指令和JAVA API)
|
3天前
|
JSON 安全 Java
淘客返利平台的API设计与安全
淘客返利平台的API设计与安全
|
3天前
|
JavaScript API
【Vue3的组合式API】超详细教程,含computed、watch、组件通信、模版引用......
【Vue3的组合式API】超详细教程,含computed、watch、组件通信、模版引用......
|
27天前
|
安全 API 数据安全/隐私保护
关于API安全设计5A原则
【6月更文挑战第1天】5A原则包括身份认证、授权、访问控制、可审计性和资产保护,是安全设计的核心要素。
|
28天前
|
Oracle 安全 Java
JAVA用Mail发送API的方法步骤教程
使用Java和Mail发送API实现自动化邮件发送,提高效率。步骤包括:1. 安装JDK并配置JAVA_HOME,2. 添加JavaMail库(可通过Maven或官网下载)。配置邮件发送涉及邮件服务器地址、端口和认证信息。创建邮件会话、邮件消息对象,然后使用Transport发送。示例代码展示完整流程。注意处理认证失败、连接问题和邮件发送失败等常见问题。
|
1天前
|
人工智能 运维 Serverless
函数计算产品使用问题之启动的实例是否有调用api接口停止功能
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。