Android笔记本springbootJava开发

接口请求身份认证的Token和RefreshToken的解决方案

2019-04-18  本文已影响440人  猫小萌的哥哥

前言

最近公司在改造接口的请求的验证,之前是登陆后返回一个token,在请求的时候动态添加到header中,以此来验证身份,当返回401直接去重新登录;现在登录返回tokenrefreshToken两个参数,拿token去添加header,当返回401时并不直接去登录而是拿refreshToken去请求一个接口,刷新得到新的tokenrefreshToken,拿到新的token再去请求当前返回401的接口,如果此时返回410则是真正的过期才需要去登录。

准备工作

正式工作

Response response = chain.proceed(builder.build());
        ResponseBody responseBody = response.body();
        BufferedSource source = responseBody.source();
        source.request(Long.MAX_VALUE);
        Buffer buffer = source.buffer();
        Charset charset = UTF8;
        MediaType contentType = responseBody.contentType();
        if (contentType != null) {
            charset = contentType.charset(UTF8);
        }
        //获取响应体的字符串
        String bodyString = buffer.clone().readString(charset);
        CustomResponse customResponse = new Gson().fromJson(bodyString, CustomResponse.class);
        String code = customResponse.getCode();//后台的返回码
        String msg = customResponse.getMsg();

        if ("401".equals(code)) {
            //todo 当返回401时去刷新token
        }
        //否则正常返回 response
Map<String, String> map = new ArrayMap<>();
        map.put("refreshToken", refreshToken);//这是我们在登录成功后返回的refreshToken,专门用于刷新操作的
        RequestBody body = NetworkUtils.setBody(map);
        Call<CustomResponse<Map<String, String>>> call = RetrofitUtils.provideClientApi().refreshToken(body);
        CustomResponse refreshResponse = call.execute().body();
        Map<String, String> mapToken = (Map<String, String>) refreshResponse.getData();
        String refreshCode = refreshResponse.getCode();
@Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();//这里的request只是为了拿到请求的url和参数,下面要重新生成request(builder.build())
        Request.Builder builder = request.newBuilder()
                .addHeader("Content-Type", "application/json; charset=UTF-8")
                .addHeader("Authorization", newToken);

        //注意:chain.proceed(这里一定不能是拿到的request,而是builder.build())
        return chain.proceed(builder.build());
    }

好了,完成

synchronized (mContext) {
            Map<String, String> map = new ArrayMap<>();
            map.put("refreshToken", refreshToken);//这是我们在登录成功后返回的refreshToken,专门用于刷新操作的
            RequestBody body = NetworkUtils.setBody(map);
            Call<CustomResponse<Map<String, String>>> call = RetrofitUtils.provideClientApi().refreshToken(body);
            CustomResponse refreshResponse = call.execute().body();
            Map<String, String> mapToken = (Map<String, String>) refreshResponse.getData();
            String refreshCode = refreshResponse.getCode();
        }

其实仔细想想,如果我们已经刷新过token了,那就直接拿最新的newToken去重新请求当前接口就好了,我们拿到最新的token肯定是需要保持成全局的,而我们所有的请求是异步的,那就可以拿到每次的request,这意味着什么?我们就可以拿到header,那之前过期的token就有了;二者一对比,一样则说明还没有刷新过token,那就先去刷新token,不一样说明已经有接口刷新过了直接拿最新newToken的去重新请求就好了。(就是一个判断就不贴代码了【偷笑】)

String oldToken = request.header("Authorization");
String oldToken = request.headers().get("Authorization");
Request.Builder builder = request.newBuilder()
                .addHeader("Content-Type", "application/json; charset=UTF-8")
                .addHeader("Authorization", newToken);
String oldJwt = response.request().headers().get("Authorization");
if ("401".equals(code)) {
            synchronized (mContext) {
                refreshToken = "获取最新的refreshToken"
                token = "获取最新的token"
                String oldToken = response.request().headers().get("Authorization");

                /**
                 * 当前请求中的jwt和本地最新的是否一样:
                 * 1、一样则说明没有进行刷新token操作不进入此 if
                 * 2、不一样则说明已经刷新过token操作了,进入此 if 拿最新的jwt直接重新发起当前的请求
                 */
                if (!token.equals(oldToken)) {
                    Request.Builder newBuilder = getBuilder(chain.request(), token);
                    return getNewResponse(chain, newBuilder);
                }

                Map<String, String> mapToken = refreshMapToken(refreshToken);
                String newToken = mapToken.get("token");
                String newRefreshToken = mapToken.get("refreshToken");
                MyApplication.setToken(newToken);//设置为全局常量
                "此处还需要的一个操作是把二者都保存到本地,不然下次登录就没了"

                Request.Builder newBuilder = getBuilder(chain.request(), newToken);
                return getNewResponse(chain, newBuilder);
            }
        }

后记:多试试、多看看、多想想,问题总会解决的;关于参考博客,我也不知道是哪一篇了,十分感谢;如有纰漏,不吝赐教!

上一篇下一篇

猜你喜欢

热点阅读