拦截器实现AccessToken

1.互联网开放平台设计:

1.需求:现在A公司与B公司进行合作,B公司需要调用A公司开放的外网接口获取数据,
如何保证外网开放接口的安全性。

2.开放平台提供者:需要提供为每个合作机构提供对应的appId,appSecret (需要appId+appSecret生成对应的accessToken)

3.基于令牌方式实现
appId (第三方合作机构,区分不同的机构) 永远不能改变
appSecret (在传输中实现加密功能,密钥) 可以发生改变
(因为如果被人知道,可以伪造请求,当发现appSecret被人知道后,可以重新生成,此时伪造请求会报错)

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

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

2.数据库表设计:
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

3.获取AccessToken:

@RequestMapping("/accessToken")
public interface AccessTokenService {

    @RequestMapping("/getAccessToken")
    ResponseBase getAccessToken(String appId,String appSecret);
}
@RestController
public class AccessTokenServiceImpl extends BaseApiService implements AccessTokenService {

    private long timeToken = 60 * 60 * 2;
    @Autowired
    private AccessTokenDao accessTokenDao;
    @Override
    public ResponseBase getAccessToken(String appId, String appSecret) {
        //先查询是否存在该机构的认证信息
        AppEntity appEntity = accessTokenDao.findApp(appId, appSecret);
        if (null == appEntity){
            return setResultError("没有存在该机构的认证信息");
        }
        //判断该机构现在是否有效
        if (1 == appEntity.getIsFlag()){
            return setResultError("您现在没有权限生成对应的AccessToken");
        }
        // ### 获取新的accessToken 之前删除之前老的accessToken
        // 从redis中删除之前的accessToken
        String accessToken = appEntity.getAccessToken();
        if (null != accessToken){
            baseRedisService.delKey(accessToken);
        }
        String newAccessToken = newAccessToken(appId);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("accessToken", newAccessToken);
        return setResultSuccess(jsonObject);
    }

    private String newAccessToken(String appId) {
        // 使用appid+appsecret 生成对应的AccessToken 保存两个小时
        String accessToken = UUID.randomUUID().toString().replace("-", "");
        // 保证在同一个事物redis 事物中
        // 生成最新的token key为accessToken value 为 appid
        baseRedisService.setString(accessToken, appId, timeToken);
        // 表中保存当前accessToken
        accessTokenDao.updateAccessToken(accessToken, appId);
        return accessToken;
    }
}

4.编写拦截器拦截请求,验证accessToken:

@Component
public class AccessTokenInterceptor extends BaseApiService implements HandlerInterceptor {
    @Autowired
    private RedisService redisService;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest,
           HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("---------------------开始进入请求地址拦截----------------------------");
        String accessToken = httpServletRequest.getParameter("accessToken");
        if (StringUtils.isEmpty(accessToken)){
            resultError("this is parameter accessToken null",httpServletResponse);
            return false;
        }
        String appId = redisService.getString(accessToken);
        if (StringUtils.isEmpty(appId)){
            //accessToken失效
            resultError("this is  accessToken Invalid",httpServletResponse);
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest,
           HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
           HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }

    public void resultError(String msg,HttpServletResponse httpServletResponse) throws IOException {
        PrintWriter writer = httpServletResponse.getWriter();
        writer.print(new JSONObject().toJSONString(setResultError(msg)));
    }
}

@Configuration
public class WebAppConfig {
	@Autowired
	private AccessTokenInterceptor accessTokenInterceptor;

	@Bean
	public WebMvcConfigurer WebMvcConfigurer() {
		return new WebMvcConfigurer() {
			public void addInterceptors(InterceptorRegistry registry) {
				registry.addInterceptor(accessTokenInterceptor).addPathPatterns("/openApi/*");
			};
		};
	}
}
@RequestMapping("/testAccessToken")
public interface TestAccessTokenService {

    @RequestMapping("/test")
    public ResponseBase getTest();
}
@RestController
public class TestAccessTokenServiceImpl extends BaseApiService implements TestAccessTokenService {

    @Override
    public ResponseBase getTest() {
        return setResultSuccess("调取接口成功");
    }
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值