首页  ·  知识 ·  架构设计
API开放接?设计之appId,appSecret,accessToken
CIO之家的朋友  程序员不圆  综合  编辑:love_bb2002   图片来源:网络
为每个合作机构创建对应的appid、app_secret,?成对应的access_token(有效期2?时),在调?外?开放接?的时候,必须传递有效的access_token。使?access_token验证通过才能正常调?开放的AP

?、开放接?设计说明:

为每个合作机构创建对应的appid、app_secret,?成对应的access_token(有效期2?时),在调?外?开放接?的时候,必须传递有效的access_token。使? access_token 验证通过才能正常调?开放的 API 接?




appid 是每个?户唯?的


app_secret 可以开发着平台更改


access_token通过 appid +  app_secret  ?成,(有效期2?时)




如:微信公众号开发调?微信接?,下?就??写?个类似于微信开发的api开放接?平台




使?流程:同调?第三?平台接?


api 开发平台申请appid ,app_secret ,或??提供给消费?


消费?通过 appid ,app_secret 获得 access_token ( 有效期2?时)


消费?调?接?携带 accessToken 参数,验证通过可以才访问接?,未提供返回错误信息



?、数据库表设计 (已下为核?字段,更多??添加)


App_Name          表?机构名称

App_ID            应?id

App_Secret        应?密钥(可更改)

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

access_token      上?次access_token

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;



三、生成Token

?具类TokenUtils

public class TokenUtils {

 @RequestMapping("/getToken")

 public static String getAccessToken() {

  return UUID.randomUUID().toString().replace("-", "");

 }

}


四、getAccessToken 接??成 accessToken

步骤:


调?接?传递 appId+appSecret


判断是否存在商户信息


判断商户信息是否有权限


?成AccessToke,根据当前appId 商户更新最新的 accessToke 到数据库


删除Redis 上次?成的AccessToke缓存,保存最新的accessToke到Redis




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.itmayiedu.base.BaseApiService;

import com.itmayiedu.base.ResponseBase;

import com.itmayiedu.entity.AppEntity;

import com.itmayiedu.mapper.AppMapper;

import com.itmayiedu.utils.BaseRedisService;

import com.itmayiedu.utils.TokenUtils;


@RestController

@RequestMapping(value = "/auth")

public class AuthController extends BaseApiService {

    /**

     * Redis

     */

    @Autowired

    private BaseRedisService baseRedisService;

    /**

     * 创建的表appEntity ,的 dao对象

     */

    @Autowired

    private AppMapper appMapper;

    /**

     * 过期时间,单位秒

     */

    private long timeToken = 60 * 60 * 2;

    /**

     * TODO    使?appId+appSecret ?成AccessToke

     * @param appEntity

     * @date  2019/12/3 0003 21:33

     * @return com.itmayiedu.base.ResponseBase

     */

    @RequestMapping("/getAccessToken")

    public ResponseBase getAccessToken(AppEntity appEntity) {

        // 使?appId + appSecret查询

        AppEntity appResult = appMapper.findApp(appEntity);

        // 判断是否存在商户信息,等同与微信开发平台申请的appid,appSecret信息是否正确

        if (appResult == null) {

            return setResultError("没有对应机构的认证信息");

        }

        //判断是否开发权限给该商户

        int isFlag = appResult.getIsFlag();

        if (isFlag == 1) {

            return setResultError("您现在没有权限?成对应的AccessToken");

        }

        // 从redis中删除之前的accessToken

        baseRedisService.delKey(appResult.getAccessToken());

        // ?成的新的accessToken 保存到 Redis,并保存到数据库

        String newAccessToken = newAccessToken(appResult.getAppId());

        //返回 accessToken,setResultSuccessData为封装返回信息,请?定义

        JSONObject jsonObject = new JSONObject();

        jsonObject.put("accessToken", newAccessToken);

        return setResultSuccessData(jsonObject);

    }

    /**

     * TODO

     * @param appId

     * @date  2019/12/3 0003 21:33

     * @return java.lang.String

     */

    private String newAccessToken(String appId) {

        // 使? appid+appsecret ?成对应的AccessToken , 保存两个?时

        String accessToken = TokenUtils.getAccessToken();

        // 保证在同?个事物redis 事物中

        // ?成最新的token, key=accessToken ,value=appid

        baseRedisService.setString(accessToken, appId, timeToken);

        // 表数据更新为最新的 accessToken,删除之前的accessToken使?

        appMapper.updateAccessToken(accessToken, appId);

        return accessToken;

    }

}



五、添加拦截器AccessTokenInterceptor 


判断请求参数 accessToken

统?拦截所有开放接?的请求,判断accessToken 是否有效

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 org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import com.alibaba.fastjson.JSONObject;

import com.fasterxml.jackson.databind.deser.Deserializers.Base;

import com.itmayiedu.base.BaseApiService;

import com.itmayiedu.utils.BaseRedisService;

/**

 * TODO    验证AccessToken 是否正确

 *

 * @date 2019/12/3 0003 21:54

 * @return

 */

@Component

public class AccessTokenInterceptor extends BaseApiService implements HandlerInterceptor {

    /**

     * redis

     */

    @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("---------------------开始进?请求地址拦截----------------------------");

        //获取到accessToken

        String accessToken = httpServletRequest.getParameter("accessToken");

        // 判断accessToken是否空

        if (StringUtils.isEmpty(accessToken)) {

            // 返回错误消息

            resultError(" this is parameter accessToken null ", httpServletResponse);

            return false;

        }

        //从redis 中获取获取到accessToken

        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 {

                           ModelAndView modelAndView) throws Exception {

        System.out.println("--------------处理请求完成后视图渲染之前的处理操作---------------");

    }

    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,

                                Object o, Exception e) throws Exception {

        System.out.println("---------------视图渲染之后的操作-------------------------0");

    }

    /**

     * TODO    返回错误提?

     * @param errorMsg

     * @param httpServletResponse

     * @date  2019/12/3 0003 21:58

     * @return void

     */

    public void resultError(String errorMsg, HttpServletResponse httpServletResponse) throws IOException {

        PrintWriter printWriter = httpServletResponse.getWriter();

        // setResultError为封装的返回信息,请?定义

        printWriter.write(new JSONObject().toJSONString(setResultError(errorMsg)));

    }



六、添加拦截器AccessTokenInterceptor 的拦截范围

添加拦截器AccessTokenInterceptor 的拦截范围/openApi 下的所有接?


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;

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 {

 @Autowired

 private AccessTokenInterceptor accessTokenInterceptor;

 @Bean

 public WebMvcConfigurer WebMvcConfigurer() {

  return new WebMvcConfigurer() {

   public void addInterceptors(InterceptorRegistry registry) {

       //  /openApi   下的所有接?

    registry.addInterceptor(accessTokenInterceptor).addPathPatterns("/openApi/*");

   };

  };

 }

}



使?流程:同调?第三?平台接?


api 开发平台申请appid,app_secret ,或??提供给消费?


消费?通过 appid,app_secret 获得 access_token ( 有效期2?时)


消费?调?接?携带 accessToken 参数,验证通过可以才访问接?,未提供返回错误信息


本文作者:CIO之家的朋友 来源:程序员不圆
CIO之家 www.ciozj.com 微信公众号:imciow
    >>频道首页  >>网站首页   纠错  >>投诉
版权声明:CIO之家尊重行业规范,每篇文章都注明有明确的作者和来源;CIO之家的原创文章,请转载时务必注明文章作者和来源;
延伸阅读