token刷新并发 java_retrofit 刷新token并发处理

文章讨论了在app开发中处理token刷新并发的两种常见方案,特别聚焦于使用Retrofit时遇到的问题。当多个接口同时请求刷新token时,由于refreshToken的唯一性,可能导致后续请求失败。作者提出了三种解决思路:使用`synchronized`关键字、`synchronized`代码块以及`ReentrantLock`。强调多线程同步操作的资源消耗,并提醒开发者掌握更多知识以解决复杂问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

情况说明

在app开发中,我们需要保证用户登录之后,如果没有在其他设备上登录,则不需要再次登录,很多都会使用token作为安全令牌,开始阶段都会在登录时候获取,一直使用到下次登录。这样的token没有什么安全性可言,所以大多app都会做token时效性处理。

刷新token流程图如下:

0dd504933b9117f65a134734c297a347.png

刷新token流程图.png

暂时我了解的方案有两种:

在获取token的时候,同时获得token的有效时间和刷新token时用的refreshToken(只允许使用一次),在请求接口的时候判断token是否在有效期内,如若在这个时间内,则继续使用旧token,不在这个时间段则根据token和RefreshToken请求token刷新接口,重新获取;并且后台也会判断token是否有效,token无效,refreshToken有效,给出错误码,可以刷新token;token无效,refreshToken无效,给出错误码,重新登录获取token。

if ((currentTime - startTime) < validTime) {

//使用原有的token

} else {

//根据refreshToken刷新token,获取新的token

}

登陆获取token,使用该token一直请求接口,后台判断token是否失效,如果失效抛出401错误,客户端在请求头中截取请求Code,如果是401错误,则刷新token,并用刷新获得的新token请求接口。

public okhttp3.Response intercept(Chain chain) throws IOException {

request = request.newBuilder()

.header(AUTH_HEADER_KEY, BEARER_HEADER_VALUE + token)

.build();

Response response = chain.proceed(request);

//判断请求接口是否发生401错误

if (response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) {

//同步刷新token,获得newToken

Request newRequest = request.newBuilder()

.removeHeader(AUTH_HEADER_KEY)

.addHeader(AUTH_HEADER_KEY, BEARER_HEADER_VALUE + newToken.getAccessToken())

.build();

response = chain.proceed(newRequest);

}

return response;

}

我们使用的是第一种方案,但是在开发过程中出现刷新token并发的情况

遇问题说明

在token失效期间,多个接口同时请求刷新token这个接口,由于refreshToken的有效性只为一次,当第一个请求接口去刷新token,当接口还没有请求成功,token还没有刷新,后面的接口请求时,token也是失效的,需要刷新。后面的其他接口在使用原来的refreshToken刷新,则会失败,接口调用错误,退回到登录页面,与当初设想的效果不符。

对于第二种方法,没有实践过。当多个接口的token失效,一同去刷新token,后台返回来的是同一个token还是不相同,安全性可靠么,并发是怎样处理的?希望广大网友有遇到这样的情况在下方留言,在下感激不尽。

问题解决思路

在retrofit中个人还没有找到可以实现多个接口并发,而且同步操作的方法。往上有人说建议使用retrofit+Rxjava可以实现,但是本人对Rx才上手还没有深入了解。所以能否解决这个问题,我还不知道。我解决问题的思路如下:

思路一

接口几乎是同时请求,那么我在请求每个接口的时候都增加一个Thread.sleep(1000);当网络比较慢的时候效果还可以,但是当网络状态良好,问题相当于没有解决。

思路二

使用handler.sendMessage();使用消息队列进行处理,问题仍然没有解决

思路三

多线程同步,每次请求都是一个异步操作,想让获取token这个过程按照顺序来,就需要同步操作或者线程队列。这个思路解决所遇到的问题。

多线程同步

解决当下的问题,有三种方法:

一是使用synchronized关键字,对方法进行同步。

public synchronized String getToken(){

final String token = "";

//对token进行有效判断,有效则使用原有的;无效则对token进行刷新操作

// :warning:刷新token的接口要使用同步操作,否则无用

//....

return token;

}

二是使用synchronized(object){}同步代码快的方法,把需要同步的操作放到“{}”内。与一是一样的

synchronized (this){

//需要同步的代码块

}

三是使用重入锁ReenreantLock实现线程同步

private Lock mLock = new ReentrantLock();

public String getToken(){

mLock.lock();

try{

//需要上锁的代码块

}finally{

mLock.unlock();

}

}

此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁

涉及知识点

synchronized关键字是用来控制线程同步的,就是在多线程的环境下,控制synchronized代码段不被多个线程同时执行。synchronized既可以加在一段代码上,也可以加在方法上。

ReentrantLock:官方说明是一个可重入的互斥锁定 Lock,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强大。ReentrantLock 将由最近成功获得锁定,并且还没有释放该锁定的线程所拥有。当锁定没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁定并返回。如果当前线程已经拥有该锁定,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。

:warning:多线程同步操作是一种耗费资源,耗时的操作,在开发中能不使用尽量不使用。

总结

解决刷新token这个问题上,需要我们了解retrofit的同步异步请求,同时需要知道如何在retrofit的请求中添加header,并用多线程同步的知识进行token的获取,至少需要了解synchronized或ReentrantLock 其中一种的用法和实现。只有掌握更多的知识,才可以解决更加艰难的问题。

参考文档

注意:本文来自简书。本站无法对本文内容的真实性、完整性、及时性、原创性提供任何保证,请您自行验证核实并承担相关的风险与后果!

CoLaBug.com遵循[CC BY-SA 4.0]分享并保持客观立场,本站不承担此类作品侵权行为的直接责任及连带责任。您有版权、意见、投诉等问题,请通过[eMail]联系我们处理,如需商业授权请联系原作者/原网站。

<think>好的,我需要帮助用户设计一个基于Android的人事管理系统,涵盖主要功能模块和技术细节。首先,我得回顾用户提供的引用内容,看看有哪些已有的技术栈和功能模块可以参考。 用户提到的引用里有几个关键点:服务端使用MyEclipse开发,客户端用Android Studio,数据库是MySQL,数据交互通过JDBC和JSP,还有Java编写API接口。这些技术组合起来就是典型的C/S架构,前端Android,后端Java Web。 接下来,功能模块方面,用户需要登录、员工信息管理、工资、考勤、部门管理、培训与奖惩。这些模块需要前后端配合。例如,登录模块需要客户端收集用户输入,发送到服务端验证,可能用HTTP或HTTPS协议,后端用JSP处理请求,Java调用JDBC查询MySQL数据库。 员工信息管理模块需要前后端的数据交互,比如增删改查操作。这里可能需要设计RESTful API,使用JSON格式传输数据。Android端用Retrofit或OkHttp库处理网络请求,解析JSON,然后显示在RecyclerView里。 工资和考勤模块可能涉及复杂的数据计算,服务端需要处理业务逻辑,比如计算薪资考虑考勤记录。数据库设计上,考勤表需要关联员工ID和日期,工资表可能关联员工ID、基本工资、奖金、扣款等字段。 部门管理模块需要树状结构,可能用部门表存储上级部门ID,实现层级关系。Android端可以用ExpandableListView展示部门结构。培训与奖惩模块可能需要上传文件或图片,这部分需要考虑文件存储,比如使用服务器本地存储或云存储服务。 技术细节方面,服务端用MyEclipse开发,整合JSP和Servlet处理HTTP请求,JDBC连接MySQL。客户端用Android Studio,界面用XML布局,网络请求用Java代码,可能需要Volley或Retrofit库。数据交互格式建议JSON,因为轻量且易解析。 安全性方面,用户提到HTTPS,所以服务端需要配置SSL证书,Android端使用HttpsURLConnection。登录凭证可以用Token机制,服务端生成Token,客户端保存并在每次请求携带。 数据库设计部分,需要创建员工表、部门表、工资表、考勤表、培训表、奖惩表等,确保外键关联正确。例如,员工表有部门ID外键,工资表有员工ID外键。 可能遇到的问题包括数据同步,比如员工信息修改后如何及更新客户端,可以考虑使用长轮询或WebSocket。另外,权限管理需要区分管理员和普通员工,服务端接口需做权限校验。 测试方面,可以使用Android模拟器,如雷电模拟器,同测试不同屏幕尺寸和系统版本。服务端部署在Tomcat或Jetty服务器上,确保并发处理能力。 最后,根据用户提供的引用,参考现有系统如小区物业管理和校园快递APP的设计,借鉴他们的模块划分和技术实现,确保人事管理系统的可行性和稳定性。</think>### 基于Android的人事管理系统设计方案 #### 一、系统架构设计 采用C/S架构模式: - **客户端**:Android Studio开发,基于Java/XML实现界面,通过HTTP/HTTPS协议与服务端通信[^3][^5] - **服务端**:MyEclipse开发,使用JSP+Servlet处理业务逻辑,JDBC连接MySQL数据库[^1][^3] #### 二、功能模块设计 ```mermaid graph TD A[人事管理系统] --> B[登录认证] A --> C[员工信息管理] A --> D[薪资管理] A --> E[考勤管理] A --> F[部门管理] A --> G[培训管理] A --> H[奖惩管理] ``` #### 三、技术实现细节 1. **客户端实现**: ```java // Android端网络请求示例(Retrofit) public interface ApiService { @POST("login") Call<LoginResponse> login(@Body LoginRequest request); @GET("employees") Call<List<Employee>> getEmployees(); } ``` 2. **服务端架构**: ``` 服务端分层结构: - 表示层(JSP) - 控制层(Servlet) - 业务逻辑层(JavaBean) - 数据访问层(JDBC) - 数据库层(MySQL)[^1] ``` 3. **数据库设计**: ```sql CREATE TABLE employee ( emp_id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50), dept_id INT, position VARCHAR(30), FOREIGN KEY (dept_id) REFERENCES department(dept_id) ); CREATE TABLE salary ( salary_id INT PRIMARY KEY, emp_id INT, base DECIMAL(10,2), bonus DECIMAL(10,2), FOREIGN KEY (emp_id) REFERENCES employee(emp_id) ); ``` #### 四、关键技术实现 1. **数据交互**: - 采用JSON格式传输数据 - 使用Volley/Retrofit处理网络请求 - 服务端通过JSP生成动态响应[^5] 2. **安全机制**: - HTTPS通信加密 - BCrypt密码哈希存储 - Session Token认证机制[^3] 3. **核心功能实现**: ```java // 服务端考勤计算逻辑示例 public class AttendanceService { public double calculateWorkHours(Date checkIn, Date checkOut) { long diff = checkOut.getTime() - checkIn.getTime(); return (diff / (1000.0 * 60 * 60)); // 转换为小 } } ``` #### 五、系统部署要求 | 组件 | 要求 | |-------------|--------------------------| | 客户端 | Android 5.0+ | | 服务端 | Tomcat 8.0+/JDK 1.8+ | | 数据库 | MySQL 5.7+ | | 开发环境 | Android Studio 4.0+ | | 测试设备 | 推荐使用雷电模拟器 | #### 六、扩展优化建议 1. 集成第三方身份认证(如企业微信) 2. 添加数据可视化报表功能 3. 实现移动端指纹/人脸识别登录 4. 采用Redis缓存高频访问数据
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值