基于AccessToken方式实现API设计
生活随笔
收集整理的這篇文章主要介紹了
基于AccessToken方式实现API设计
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
互聯網開放平臺設計
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设计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Web常见攻击手段总结
- 下一篇: 互联网API开放平台安全设计-基于OAu