webView系列(十)----自动登录(刷新token持久化登录)

一、前言

在上一篇博文webView系列(九)—-登录验证中,我们将到了登录验证,验证token失效后,就会到登陆页面重新登陆,这样用户觉得登陆的比较麻烦,想达到登陆一次,就很久都不需要登陆了,只要一直使用APP就不会,几天不使用都不会退出登录。为达到这样的效果,我们将讲解自动登录。

二、自动登录

/**
 * api>=21调用
 * @param view
 * @param request
 * @return
 */
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, final WebResourceRequest request) {
    
    if (request != null && request.getUrl() != null && request.getMethod().equalsIgnoreCase("get")) {
        String scheme = request.getUrl().getScheme().trim();
        if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) {
            if (request.getUrl().toString().contains(".html")) {
                try {
                    URL url = new URL(InjectParamsUtil.verrificationToken(request.getUrl().toString()));
                    URLConnection connection = url.openConnection();
                    if (connection.getInputStream().toString().length() < 120) {
                        String value = IOUtils.toString(connection.getInputStream(), "UTF-8");
                        if (value.startsWith("{")) {
                            HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);
                            if (httpResult != null) {
                                if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {
                                    HttpResult refreshHttpResult = RefreshTokenSynchronizationRequest.synchronizationRefreshToken();
                                    if (refreshHttpResult != null && Constants.SUCCESS_CODE.equals(refreshHttpResult.getCode())) {
                                        runOnUiThread(new Runnable() {
                                            @Override
                                            public void run() {
                                                String newUrl = InjectParamsUtil.injectIsParams(request.getUrl().toString());
                                                LogUtil.e("newUrl-->" + newUrl);
                                                //刷新
                                                isRefresh = true;
                                                mWebView.loadUrl(newUrl);
                                            }
                                        });
                                    } else {
                                        setResult(LOGIN_OUT_RESULT);
                                        finish();
                                    }
                                }
                            }
                        }
                    } else {
                        connection.getInputStream().close();
                    }
                    return null;
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    return null;
}

/**
 * api<21调用
 * @param view
 * @param url
 * @return
 */
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
   
    if (url.contains(".html")) {
        try {
            URL url1 = new URL(InjectParamsUtil.verrificationToken(url));
            URLConnection connection = url1.openConnection();
            if (connection.getInputStream().toString().length() < 120) {
                String value = IOUtils.toString(connection.getInputStream(), "UTF-8");
                if (value.startsWith("{")) {
                    HttpResult httpResult = JSONObject.parseObject(value, HttpResult.class);
                    if (httpResult != null) {
                        if (Constants.LOGIN_OUT_CODE.equals(httpResult.getCode())) {
                            HttpResult refreshHttpResult = RefreshTokenSynchronizationRequest.synchronizationRefreshToken();
                            if (refreshHttpResult != null && Constants.SUCCESS_CODE.equals(refreshHttpResult.getCode())) {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        String newUrl = InjectParamsUtil.injectIsParams(url);
                                        LogUtil.e("newUrl-->" + newUrl);
                                        //刷新
                                        isRefresh = true;
                                        mWebView.loadUrl(newUrl);
                                    }
                                });
                            } else {
                                setResult(LOGIN_OUT_RESULT);
                                finish();
                            }
                        }
                    }
                }
            } else {
                connection.getInputStream().close();
            }

            return null;
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return null;
}

看了上面的代码,是不是觉得很熟悉,没错,这个就是登陆验证的代码,只不过有了一点点的不同而已。

三、自动登录流程

  1. 登录验证
  2. token失效,刷新token
  3. 刷新token成功,替换掉token,进行重新加载;刷新token失败,则退出登录,让用户自己重新登录。

从上面的流程来看,流程很清晰明了,注意的就是在刷新token的那一块。

四、刷新token

  • 刷新token我们这里就不能使用异步请求了,这里要使用同步请求

4.1、RefreshTokenSynchronizationRequest类

/**
 * 同步请求刷新token
 *
 * @author Freak
 * @date 2019/6/15.
 */

public class RefreshTokenSynchronizationRequest {
    private static ApiServer apiService = HttpMethods.getInstance().create(ApiServer.class);

    public static synchronized HttpResult synchronizationRefreshToken() throws IOException {
        final Call<ResponseBody> call = apiService.synchronizationRefreshToken(
                (String) SPUtils.get(App.getInstance().getApplicationContext(), Constants.REFRESH_TOKEN, ""));
        //  call对象执行同步请求
        String result = RefreshTokenResponse.getResponseBody(call.execute().body());
        HttpResult refreshHttpResult = JSONObject.parseObject(result, HttpResult.class);
        LogUtil.e("result-->" + refreshHttpResult);
        if (refreshHttpResult != null) {
            if (Constants.SUCCESS_CODE.equals(refreshHttpResult.getCode())) {
                //登陆信息的保存
                LoginEntity loginEntity = JSONObject.parseObject(new Gson().toJson(refreshHttpResult.getData()), LoginEntity.class);
                //                SPUtils.saveLoginEntity(App.getInstance().getApplicationContext(), loginEntity);
            }
        }
        return refreshHttpResult;
    }
}

我们都知道response.body().string(),只能读取一次,这里我们需要做一下出来,把response的数据clone了一份,这样就不会只能读取一次了。这里是为了复用接口请求(后面再讲,具体的可以查看okhttp系列的博文)

五、response.body().string()只能读取一次问题解决

public class RefreshTokenResponse {
    public static String getResponseBody(ResponseBody responseBody) throws IOException {
        BufferedSource source = responseBody.source();
        // 获取全部body的数据
        source.request(Long.MAX_VALUE);
        Buffer buffer = source.buffer();
        // 在读取缓存去之前clone数据,解决response.body().string()只能读取一次的问题
        String responseBodyString = buffer.clone().readString(Charset.forName("UTF-8"));
        return responseBodyString;
    }
}

六、刷新token机制介绍

一般的情况下,我们做的接口可能就只会有一个token的字段,需要刷新token的话,就要多一个字段去刷新token,这里才有的是OAuth 2登陆授权。具体的OAuth 2了解可到博文OAuth 2 深入介绍中去了解,这里就不做介绍了。

七、注意事项

自动登录并不是说登录一次就不再需要登陆了,这个登陆的失效与刷新token的那个字段refreshToken的过期时长有关系。

举个栗子:

在你登陆成功之后,后台会给你返回access_token、refresh_token、expires_in(token过期时长)等字段,我们在access_token过期之后,我们会拿refresh_token去进行access_token的刷新,更新新的token和更新token的过期时长。但是在用户很久没有使用APP的时候,此时,refresh_token的有效时长也到期了,这时候,你拿refresh_token去刷新token,就会返回刷新失败,这时候,就需要用户去重新登录了。

所以,自动登录并不是能达到永久登录,登录时长跟后台设置的access_token和refresh_token有效时长有关。

 

    原文作者:freak_csh
    原文地址: https://blog.csdn.net/freak_csh/article/details/95530614
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞