互联网开放平台设计

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

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

2.常用解决办法:

2.1 使用加签名方式,防止篡改数据

2.2 使用Https加密传输

2.3 搭建OAuth2.0认证授权

2.4 使用令牌方式

2.5 搭建网关实现黑名单和白名单

使用令牌方式搭建搭建API开放平台

原理:为每个合作机构创建对应的appid、app_secret,生成对应的access_token(有效期2小时),在调用外网开放接口的时候,必须传递有效的access_token。

App_Name       表示机构名称

App_ID          应用id

App_Secret      应用密钥  (可更改)

Is_flag           是否可用 (是否对某个机构开放)

access_token  上一次access_token

select * from m_appCREATE 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;localhost:8080/auth/getAccessToken?appId=77c76f3a1eba44f189135d6c47781fb1&appSecret=3b189c084b844359b45ab1c932880d0577c76f3a1eba44f189135d6c47781fb13b189c084b844359b45ab1c932880d05insert into m_app values(null,'阿里巴巴','77c76f3a1eba44f189135d6c47781fb1','3b189c084b844359b45ab1c932880d05','0','abcd');{rtnCode: 200,msg: "success",data: {accessToken: "598058b15ce04ad58e2f07262227c8df"}
}localhost:8080/openApi/getUser?accessToken=bfbb527574a64c1688adf4c9c5d98b93{rtnCode: 200,msg: "success",data: {accessToken: "bfbb527574a64c1688adf4c9c5d98b93"}
}localhost:8080/openApi/getUser?accessToken=bfbb527574a64c1688adf4c9c5d98b93{rtnCode: 200,msg: "获取会员信息接口",data: null
}{msg: " this is accessToken Invalid ",rtnCode: 500
}localhost:8080/openApi/getUser?accessToken=7b9f5c6aa09a4f898605f57adec26a7c
package com.learn.handler;import java.io.IOException;
import java.io.PrintWriter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import com.alibaba.fastjson.JSONObject;
import com.learn.base.BaseApiService;
import com.learn.utils.BaseRedisService;//验证AccessToken 是否正确
@Component
public class AccessTokenInterceptor extends BaseApiService implements HandlerInterceptor {@Autowiredprivate 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 accessTokenresultError(" 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)));}}
package com.learn.handler;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebAppConfig {@Autowiredprivate AccessTokenInterceptor accessTokenInterceptor;@Beanpublic WebMvcConfigurer WebMvcConfigurer() {return new WebMvcConfigurer() {public void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(accessTokenInterceptor).addPathPatterns("/openApi/*");};};}}
package com.learn.api.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSONObject;
import com.learn.base.BaseApiService;
import com.learn.base.ResponseBase;
import com.learn.entity.AppEntity;
import com.learn.mapper.AppMapper;
import com.learn.utils.BaseRedisService;
import com.learn.utils.TokenUtils;// 创建获取getAccessToken
@RestController
@RequestMapping(value = "/auth")
public class AuthController extends BaseApiService {@Autowiredprivate BaseRedisService baseRedisService;private long timeToken = 60 * 60 * 2;@Autowiredprivate 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中删除之前的accessTokenString accessToken = appResult.getAccessToken();baseRedisService.delKey(accessToken);// 生成的新的accessTokenString 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 为 appidbaseRedisService.setString(accessToken, appId, timeToken);// 表中保存当前accessTokenappMapper.updateAccessToken(accessToken, appId);return accessToken;}
}
package com.learn.api.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.learn.base.BaseApiService;
import com.learn.base.ResponseBase;@RestController
@RequestMapping("/openApi")
public class MemberController extends BaseApiService {@RequestMapping("/getUser")public ResponseBase getUser() {return setResultSuccess("获取会员信息接口");}
}
package com.learn.base;import org.springframework.stereotype.Component;import com.learn.utils.Constants;@Component
public class BaseApiService {public ResponseBase setResultError(Integer code, String msg) {return setResult(code, msg, null);}// 返回错误,可以传msgpublic ResponseBase setResultError(String msg) {return setResult(Constants.HTTP_RES_CODE_500, msg, null);}// 返回成功,可以传data值public ResponseBase setResultSuccessData(Object data) {return setResult(Constants.HTTP_RES_CODE_200, Constants.HTTP_RES_CODE_200_VALUE, data);}public ResponseBase setResultSuccessData(Integer code, Object data) {return setResult(code, Constants.HTTP_RES_CODE_200_VALUE, data);}// 返回成功,沒有data值public ResponseBase setResultSuccess() {return setResult(Constants.HTTP_RES_CODE_200, Constants.HTTP_RES_CODE_200_VALUE, null);}// 返回成功,沒有data值public ResponseBase setResultSuccess(String msg) {return setResult(Constants.HTTP_RES_CODE_200, msg, null);}// 通用封装public ResponseBase setResult(Integer code, String msg, Object data) {return new ResponseBase(code, msg, data);}}
package com.learn.base;import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;@Getter
@Setter
@Slf4j
public class ResponseBase {private Integer rtnCode;private String msg;private Object data;public ResponseBase() {}public ResponseBase(Integer rtnCode, String msg, Object data) {super();this.rtnCode = rtnCode;this.msg = msg;this.data = data;}public Integer getRtnCode() {return rtnCode;}public void setRtnCode(Integer rtnCode) {this.rtnCode = rtnCode;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public static void main(String[] args) {ResponseBase responseBase = new ResponseBase();responseBase.setData("123456");responseBase.setMsg("success");responseBase.setRtnCode(200);System.out.println(responseBase.toString());}@Overridepublic String toString() {return "ResponseBase [rtnCode=" + rtnCode + ", msg=" + msg + ", data=" + data + "]";}}
package com.learn.entity;public class AppEntity {private long id;private String appId;private String appName;private String appSecret;private String accessToken;private int isFlag;public long getId() {return id;}public void setId(long id) {this.id = id;}public String getAppId() {return appId;}public void setAppId(String appId) {this.appId = appId;}public String getAppName() {return appName;}public void setAppName(String appName) {this.appName = appName;}public String getAppSecret() {return appSecret;}public void setAppSecret(String appSecret) {this.appSecret = appSecret;}public String getAccessToken() {return accessToken;}public void setAccessToken(String accessToken) {this.accessToken = accessToken;}public int getIsFlag() {return isFlag;}public void setIsFlag(int isFlag) {this.isFlag = isFlag;}@Overridepublic String toString() {return "AppEntity [id=" + id + ", appId=" + appId + ", appName=" + appName + ", appSecret=" + appSecret+ ", accessToken=" + accessToken + ", isFlag=" + isFlag + "]";}}
package com.learn.mapper;import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;import com.learn.entity.AppEntity;public interface AppMapper {@Select("SELECT ID AS ID ,APP_NAME AS appName, app_id as appId, app_secret as appSecret ,is_flag as isFlag , access_token as accessToken from m_app "+ "where app_id=#{appId} and app_secret=#{appSecret}  ")AppEntity findApp(AppEntity appEntity);@Select("SELECT ID AS ID ,APP_NAME AS appName, app_id as appId, app_secret as appSecret ,is_flag as isFlag  access_token as accessToken from m_app "+ "where app_id=#{appId} and app_secret=#{appSecret}  ")AppEntity findAppId(@Param("appId") String appId);@Update(" update m_app set access_token =#{accessToken} where app_id=#{appId} ")int updateAccessToken(@Param("accessToken") String accessToken, @Param("appId") String appId);
}
package com.learn.utils;import java.util.concurrent.TimeUnit;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;@Component
public class BaseRedisService {@Autowiredprivate StringRedisTemplate stringRedisTemplate;public void setString(String key, Object data, Long timeout) {if (data instanceof String) {String value = (String) data;stringRedisTemplate.opsForValue().set(key, value);}if (timeout != null) {stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);}}public Object getString(String key) {return stringRedisTemplate.opsForValue().get(key);}public void delKey(String key) {stringRedisTemplate.delete(key);}}
package com.learn.utils;public interface Constants {// 响应请求成功String HTTP_RES_CODE_200_VALUE = "success";// 系统错误String HTTP_RES_CODE_500_VALUE = "fial";// 响应请求成功codeInteger HTTP_RES_CODE_200 = 200;// 系统错误Integer HTTP_RES_CODE_500 = 500;// 未关联QQ账号Integer HTTP_RES_CODE_201 = 201;// 发送邮件String MSG_EMAIL = "email";// 会员tokenString TOKEN_MEMBER = "TOKEN_MEMBER";// 支付tokenString TOKEN_PAY = "TOKEN_pay";// 支付成功String PAY_SUCCESS = "success";// 支付白String PAY_FAIL = "fail";// 用户有效期 90天Long TOKEN_MEMBER_TIME = (long) (60 * 60 * 24 * 90);int COOKIE_TOKEN_MEMBER_TIME = (60 * 60 * 24 * 90);Long PAY_TOKEN_MEMBER_TIME = (long) (60 * 15);// cookie 会员 totoken 名称String COOKIE_MEMBER_TOKEN = "cookie_member_token";}
package com.learn.utils;import java.util.UUID;import org.springframework.web.bind.annotation.RequestMapping;public class TokenUtils {@RequestMapping("/getToken")public static String getAccessToken() {return UUID.randomUUID().toString().replace("-", "");}public static void main(String[] args) {String a = getAccessToken();System.out.println(a);}}
package com.learn;import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@MapperScan("com.learn.mapper")
@SpringBootApplication
public class AcessTokenA {public static void main(String[] args) {SpringApplication.run(AcessTokenA.class, args);}}
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jspspring.datasource.url=jdbc:mysql://localhost:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver########################################################
###Redis (RedisConfiguration)
########################################################
spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=123456
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=8
spring.redis.pool.max-wait=-1
spring.redis.timeout=5000
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.learn</groupId><artifactId>accesstoken_projectb</artifactId><version>0.0.1-SNAPSHOT</version><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.0.RELEASE</version></parent><dependencies><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.1.1</version></dependency><!-- mysql 依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- SpringBoot 对lombok 支持 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- SpringBoot web 核心组件 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></dependency><!-- SpringBoot 外部tomcat支持 --><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId></dependency><!-- springboot-log4j --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-log4j</artifactId><version>1.3.8.RELEASE</version></dependency><!-- springboot-aop 技术 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- https://mvnrepository.com/artifact/commons-lang/commons-lang --><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency><!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId></dependency><!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.47</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version></dependency></dependencies></project>

基于AccessToken方式实现API设计相关推荐

  1. 画出c语言流程图 万年历,基于ARM7的电子万年历设计

    基于ARM7的电子万年历设计 成 绩 评 定 表 学生姓名 匡克新 班级学号 专 业 通信工程 课程设计题目 基于ARM7的电子万年历设计 评 语 组长签字: 成绩 日期 2015 年 7 月19 日 ...

  2. 基于http协议的api接口对于客户端的身份认证方式以及安全措施[转]

    基于http协议的api接口对于客户端的身份认证方式以及安全措施 由于http是无状态的,所以正常情况下在浏览器浏览网页,服务器都是通过访问者的cookie(cookie中存储的jsessionid) ...

  3. 基于iReport5.5+JavaBean+Struts2(注解方式)的报表设计与查看

    基于iReport5.5+JavaBean+Struts2(注解方式)的报表设计与查看 一.  安装iReport 二.  配置Datasource.新建一个报表 三.  配置JavaBean数据源 ...

  4. RESTful API 设计最佳实践

    2019独角兽企业重金招聘Python工程师标准>>> 背景 目前互联网上充斥着大量的关于RESTful API(为方便,下文中"RESTful API "简写为 ...

  5. 我所理解的RESTful Web API [设计篇]

    <我所理解的RESTful Web API [Web标准篇]>Web服务已经成为了异质系统之间的互联与集成的主要手段,在过去一段不短的时间里,Web服务几乎清一水地采用SOAP来构建.构建 ...

  6. python调用lib_基于python调用libvirt API

    基于python调用libvirt API 1.程序代码 #!/usr/bin/python import libvirt import sys def createConnection(): con ...

  7. 微服务API设计的实践与思考总结

    点击上方"朱小厮的博客",选择"设为星标" 后台回复"书",获取后台回复"k8s",可领取k8s资料 随着微服务的越来越 ...

  8. 阿里研究员谷朴:API 设计最佳实践的思考

    2019独角兽企业重金招聘Python工程师标准>>> API是软件系统的核心,而软件系统的复杂度Complexity是大规模软件系统能否成功最重要的因素.但复杂度Complexit ...

  9. 基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践和原则

    前言 上一篇 基于ABP落地领域驱动设计-01.全景图 概述了DDD理论和对应的解决方案.项目组成.项目引用关系,以及基于ABP落地DDD的通用原则.从这本篇开始,会更加深入地介绍在基于 ABP Fr ...

最新文章

  1. 软件架构师证书有用吗_健康管理师证书在求职时有用吗?
  2. 微软学者 | 郭达雅:瞄准科研目标主动出击,挑战“不可思议”
  3. 【 FPGA 】时钟简介
  4. Symantec(赛门铁克)非受管检测
  5. Tomcat学习总结(10)——Tomcat多实例冗余部署
  6. 现在新电脑主板带WiFi,实不实用,稳定吗?
  7. Careercup | Chapter 3
  8. 【mysql乱码】解决php中向mysql插入中文数据乱码的问题
  9. 0.618 与 1.414
  10. matlab 可视化 —— axis
  11. java 国家名称排序_对5个国家的名称进行排序详细解析
  12. centos安装python3、redis和虚拟环境
  13. word中如何替换一些特殊符号
  14. 如何在官网下载hbase
  15. docker在centos7中run时遇到的坑?
  16. SpringBoot实现短信验证码校验
  17. 学3d游戏建模要用到什么软件?一般用哪个软件?
  18. api 接口响应数据格式有哪些
  19. xiunobbs回帖时间排序修改
  20. 无效的证书、相同的序列号、SEC_ERROR_REUSED_ISSUER_AND_SERIAL

热门文章

  1. ASP.NET Core:CMD命令行+记事本 创建Console程序和Web Application
  2. 嵌入式C语言之位运算 ..|.~.
  3. Asp.Net函数集
  4. Python 的文件IO相关操作说明
  5. 大话设计模式—单例模式
  6. 区块链行业级应用服务商识数信科获千万元天使轮融资...
  7. Python学习笔记__4.1章 高阶函数
  8. 【Android进阶学习】Http编程之HttpClient
  9. 输出多个重复字符或字符串
  10. Docker介绍与安装使用(一)