Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/yudao-cloud
# Conflicts: # yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/cn/iocoder/yudao/framework/tenant/core/security/TenantSecurityWebFilter.java # yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/controller/admin/oauth2/OAuth2OpenController.java # yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2ApproveServiceImpl.java # yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2CodeServiceImpl.java # yudao-module-system/yudao-module-system-server/src/main/java/cn/iocoder/yudao/module/system/service/oauth2/OAuth2GrantServiceImpl.javapull/205/MERGE
commit
1b2abcc10e
|
@ -33,7 +33,7 @@
|
||||||
<mybatis-plus-join.version>1.5.4</mybatis-plus-join.version>
|
<mybatis-plus-join.version>1.5.4</mybatis-plus-join.version>
|
||||||
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
|
<dynamic-datasource.version>4.3.1</dynamic-datasource.version>
|
||||||
<easy-trans.version>3.0.6</easy-trans.version>
|
<easy-trans.version>3.0.6</easy-trans.version>
|
||||||
<redisson.version>3.41.0</redisson.version>
|
<redisson.version>3.50.0</redisson.version>
|
||||||
<dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
|
<dm8.jdbc.version>8.1.3.140</dm8.jdbc.version>
|
||||||
<kingbase.jdbc.version>8.6.0</kingbase.jdbc.version>
|
<kingbase.jdbc.version>8.6.0</kingbase.jdbc.version>
|
||||||
<opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
|
<opengauss.jdbc.version>5.1.0</opengauss.jdbc.version>
|
||||||
|
|
|
@ -15,10 +15,10 @@ import cn.iocoder.yudao.framework.web.core.handler.GlobalExceptionHandler;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
|
||||||
import javax.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import javax.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ public class TenantSecurityWebFilter extends ApiRequestFilter {
|
||||||
if (tenantId == null) {
|
if (tenantId == null) {
|
||||||
tenantId = user.getTenantId();
|
tenantId = user.getTenantId();
|
||||||
TenantContextHolder.setTenantId(tenantId);
|
TenantContextHolder.setTenantId(tenantId);
|
||||||
// 如果传递了租户编号,则进行比对租户编号,避免越权问题
|
// 如果传递了租户编号,则进行比对租户编号,避免越权问题
|
||||||
} else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {
|
} else if (!Objects.equals(user.getTenantId(), TenantContextHolder.getTenantId())) {
|
||||||
log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
|
log.error("[doFilterInternal][租户({}) User({}/{}) 越权访问租户({}) URL({}/{})]",
|
||||||
user.getTenantId(), user.getId(), user.getUserType(),
|
user.getTenantId(), user.getId(), user.getUserType(),
|
||||||
|
@ -101,13 +101,14 @@ public class TenantSecurityWebFilter extends ApiRequestFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isIgnoreUrl(HttpServletRequest request) {
|
private boolean isIgnoreUrl(HttpServletRequest request) {
|
||||||
|
String apiUri = request.getRequestURI().substring(request.getContextPath().length());
|
||||||
// 快速匹配,保证性能
|
// 快速匹配,保证性能
|
||||||
if (CollUtil.contains(tenantProperties.getIgnoreUrls(), request.getRequestURI())) {
|
if (CollUtil.contains(tenantProperties.getIgnoreUrls(), apiUri)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// 逐个 Ant 路径匹配
|
// 逐个 Ant 路径匹配
|
||||||
for (String url : tenantProperties.getIgnoreUrls()) {
|
for (String url : tenantProperties.getIgnoreUrls()) {
|
||||||
if (pathMatcher.match(url, request.getRequestURI())) {
|
if (pathMatcher.match(url, apiUri)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,11 @@ public class BpmProcessInstanceStatusEvent extends ApplicationEvent {
|
||||||
*/
|
*/
|
||||||
@NotNull(message = "流程实例的状态不能为空")
|
@NotNull(message = "流程实例的状态不能为空")
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
/**
|
||||||
|
* 流程实例结束的原因
|
||||||
|
*/
|
||||||
|
private String reason;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 流程实例对应的业务标识
|
* 流程实例对应的业务标识
|
||||||
* 例如说,请假
|
* 例如说,请假
|
||||||
|
|
|
@ -119,8 +119,9 @@ public interface BpmProcessInstanceConvert {
|
||||||
@Mapping(source = "from.id", target = "to.id", ignore = true)
|
@Mapping(source = "from.id", target = "to.id", ignore = true)
|
||||||
void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to);
|
void copyTo(BpmProcessDefinitionInfoDO from, @MappingTarget BpmProcessDefinitionRespVO to);
|
||||||
|
|
||||||
default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance, Integer status) {
|
default BpmProcessInstanceStatusEvent buildProcessInstanceStatusEvent(Object source, ProcessInstance instance,
|
||||||
return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status)
|
Integer status, String reason) {
|
||||||
|
return new BpmProcessInstanceStatusEvent(source).setId(instance.getId()).setStatus(status).setReason(reason)
|
||||||
.setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey());
|
.setProcessDefinitionKey(instance.getProcessDefinitionKey()).setBusinessKey(instance.getBusinessKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,10 +134,10 @@ public interface BpmProcessInstanceConvert {
|
||||||
|
|
||||||
default BpmMessageSendWhenProcessInstanceRejectReqDTO buildProcessInstanceRejectMessage(ProcessInstance instance, String reason) {
|
default BpmMessageSendWhenProcessInstanceRejectReqDTO buildProcessInstanceRejectMessage(ProcessInstance instance, String reason) {
|
||||||
return new BpmMessageSendWhenProcessInstanceRejectReqDTO()
|
return new BpmMessageSendWhenProcessInstanceRejectReqDTO()
|
||||||
.setProcessInstanceName(instance.getName())
|
.setProcessInstanceName(instance.getName())
|
||||||
.setProcessInstanceId(instance.getId())
|
.setProcessInstanceId(instance.getId())
|
||||||
.setReason(reason)
|
.setReason(reason)
|
||||||
.setStartUserId(NumberUtils.parseLong(instance.getStartUserId()));
|
.setStartUserId(NumberUtils.parseLong(instance.getStartUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
default BpmProcessInstanceBpmnModelViewRespVO buildProcessInstanceBpmnModelView(HistoricProcessInstance processInstance,
|
default BpmProcessInstanceBpmnModelViewRespVO buildProcessInstanceBpmnModelView(HistoricProcessInstance processInstance,
|
||||||
|
@ -153,7 +154,7 @@ public interface BpmProcessInstanceConvert {
|
||||||
// 基本信息
|
// 基本信息
|
||||||
respVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmProcessInstanceRespVO.class, o -> o
|
respVO.setProcessInstance(BeanUtils.toBean(processInstance, BpmProcessInstanceRespVO.class, o -> o
|
||||||
.setStatus(FlowableUtils.getProcessInstanceStatus(processInstance)))
|
.setStatus(FlowableUtils.getProcessInstanceStatus(processInstance)))
|
||||||
.setStartUser(buildUser(processInstance.getStartUserId(), userMap, deptMap)));
|
.setStartUser(buildUser(processInstance.getStartUserId(), userMap, deptMap)));
|
||||||
respVO.setTasks(convertList(taskInstances, task -> BeanUtils.toBean(task, BpmTaskRespVO.class)
|
respVO.setTasks(convertList(taskInstances, task -> BeanUtils.toBean(task, BpmTaskRespVO.class)
|
||||||
.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task))
|
.setStatus(FlowableUtils.getTaskStatus(task)).setReason(FlowableUtils.getTaskReason(task))
|
||||||
.setAssigneeUser(buildUser(task.getAssignee(), userMap, deptMap))
|
.setAssigneeUser(buildUser(task.getAssignee(), userMap, deptMap))
|
||||||
|
@ -179,8 +180,8 @@ public interface BpmProcessInstanceConvert {
|
||||||
}
|
}
|
||||||
|
|
||||||
default UserSimpleBaseVO buildUser(Long userId,
|
default UserSimpleBaseVO buildUser(Long userId,
|
||||||
Map<Long, AdminUserRespDTO> userMap,
|
Map<Long, AdminUserRespDTO> userMap,
|
||||||
Map<Long, DeptRespDTO> deptMap) {
|
Map<Long, DeptRespDTO> deptMap) {
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -960,7 +960,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService
|
||||||
|
|
||||||
// 3. 发送流程实例的状态事件
|
// 3. 发送流程实例的状态事件
|
||||||
processInstanceEventPublisher.sendProcessInstanceResultEvent(
|
processInstanceEventPublisher.sendProcessInstanceResultEvent(
|
||||||
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status));
|
BpmProcessInstanceConvert.INSTANCE.buildProcessInstanceStatusEvent(this, instance, status, reason));
|
||||||
|
|
||||||
// 4. 流程后置通知
|
// 4. 流程后置通知
|
||||||
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
|
if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
|
||||||
|
|
|
@ -35,6 +35,14 @@ tenant-id: {{adminTenantId}}
|
||||||
|
|
||||||
grant_type=password&username=admin&password=admin123&scope=user.read
|
grant_type=password&username=admin&password=admin123&scope=user.read
|
||||||
|
|
||||||
|
### 请求 /system/oauth2/token + client_credentials 接口 => 成功
|
||||||
|
POST {{baseUrl}}/system/oauth2/token
|
||||||
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
Authorization: Basic ZGVmYXVsdDphZG1pbjEyMw==
|
||||||
|
tenant-id: {{adminTenantId}}
|
||||||
|
|
||||||
|
grant_type=client_credentials&scope=user.read
|
||||||
|
|
||||||
### 请求 /system/oauth2/token + refresh_token 接口 => 成功
|
### 请求 /system/oauth2/token + refresh_token 接口 => 成功
|
||||||
POST {{baseUrl}}/system/oauth2/token
|
POST {{baseUrl}}/system/oauth2/token
|
||||||
Content-Type: application/x-www-form-urlencoded
|
Content-Type: application/x-www-form-urlencoded
|
||||||
|
|
|
@ -21,17 +21,17 @@ import cn.iocoder.yudao.module.system.service.oauth2.OAuth2ClientService;
|
||||||
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService;
|
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2GrantService;
|
||||||
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
|
import cn.iocoder.yudao.module.system.service.oauth2.OAuth2TokenService;
|
||||||
import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils;
|
import cn.iocoder.yudao.module.system.util.oauth2.OAuth2Utils;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.Parameters;
|
import io.swagger.v3.oas.annotations.Parameters;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
import jakarta.annotation.security.PermitAll;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.annotation.security.PermitAll;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -94,6 +94,7 @@ public class OAuth2OpenController {
|
||||||
@Parameter(name = "scope", example = "user_info"),
|
@Parameter(name = "scope", example = "user_info"),
|
||||||
@Parameter(name = "refresh_token", example = "123424233"),
|
@Parameter(name = "refresh_token", example = "123424233"),
|
||||||
})
|
})
|
||||||
|
@SuppressWarnings("EnhancedSwitchMigration")
|
||||||
public CommonResult<OAuth2OpenAccessTokenRespVO> postAccessToken(HttpServletRequest request,
|
public CommonResult<OAuth2OpenAccessTokenRespVO> postAccessToken(HttpServletRequest request,
|
||||||
@RequestParam("grant_type") String grantType,
|
@RequestParam("grant_type") String grantType,
|
||||||
@RequestParam(value = "code", required = false) String code, // 授权码模式
|
@RequestParam(value = "code", required = false) String code, // 授权码模式
|
||||||
|
|
|
@ -7,13 +7,16 @@ import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ApproveDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ApproveMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2ApproveMapper;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@ import cn.hutool.core.util.IdUtil;
|
||||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2CodeMapper;
|
import cn.iocoder.yudao.module.system.dal.mysql.oauth2.OAuth2CodeMapper;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,9 @@ import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2CodeDO;
|
||||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||||
import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
|
import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
|
import cn.iocoder.yudao.module.system.service.auth.AdminAuthService;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
|
@ -86,8 +86,8 @@ public class OAuth2GrantServiceImpl implements OAuth2GrantService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OAuth2AccessTokenDO grantClientCredentials(String clientId, List<String> scopes) {
|
public OAuth2AccessTokenDO grantClientCredentials(String clientId, List<String> scopes) {
|
||||||
// TODO 芋艿:项目中使用 OAuth2 解决的是三方应用的授权,内部的 SSO 等问题,所以暂时不考虑 client_credentials 这个场景
|
// 特殊:https://yuanbao.tencent.com/bot/app/share/chat/wFj642xSZHHx
|
||||||
throw new UnsupportedOperationException("暂时不支持 client_credentials 授权模式");
|
return oauth2TokenService.createAccessToken(0L, UserTypeEnum.ADMIN.getValue(), clientId, scopes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -197,6 +197,9 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||||
* @return 用户信息
|
* @return 用户信息
|
||||||
*/
|
*/
|
||||||
private Map<String, String> buildUserInfo(Long userId, Integer userType) {
|
private Map<String, String> buildUserInfo(Long userId, Integer userType) {
|
||||||
|
if (userId == null || userId <= 0) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
|
if (userType.equals(UserTypeEnum.ADMIN.getValue())) {
|
||||||
AdminUserDO user = adminUserService.getUser(userId);
|
AdminUserDO user = adminUserService.getUser(userId);
|
||||||
return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname())
|
return MapUtil.builder(LoginUser.INFO_KEY_NICKNAME, user.getNickname())
|
||||||
|
@ -205,7 +208,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||||
// 注意:目前 Member 暂时不读取,可以按需实现
|
// 注意:目前 Member 暂时不读取,可以按需实现
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
return null;
|
throw new IllegalArgumentException("未知用户类型:" + userType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String generateAccessToken() {
|
private static String generateAccessToken() {
|
||||||
|
|
|
@ -135,13 +135,6 @@ public class OAuth2GrantServiceImplTest extends BaseMockitoUnitTest {
|
||||||
refreshToken, clientId));
|
refreshToken, clientId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testGrantClientCredentials() {
|
|
||||||
assertThrows(UnsupportedOperationException.class,
|
|
||||||
() -> oauth2GrantService.grantClientCredentials(randomString(), emptyList()),
|
|
||||||
"暂时不支持 client_credentials 授权模式");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRevokeToken_clientIdError() {
|
public void testRevokeToken_clientIdError() {
|
||||||
// 准备参数
|
// 准备参数
|
||||||
|
|
|
@ -236,6 +236,7 @@ public class OAuth2TokenServiceImplTest extends BaseDbAndRedisUnitTest {
|
||||||
public void testCheckAccessToken_refreshToken() {
|
public void testCheckAccessToken_refreshToken() {
|
||||||
// mock 数据(访问令牌)
|
// mock 数据(访问令牌)
|
||||||
OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class)
|
OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class)
|
||||||
|
.setUserId(0L)
|
||||||
.setExpiresTime(LocalDateTime.now().plusDays(1));
|
.setExpiresTime(LocalDateTime.now().plusDays(1));
|
||||||
oauth2RefreshTokenMapper.insert(refreshTokenDO);
|
oauth2RefreshTokenMapper.insert(refreshTokenDO);
|
||||||
// 准备参数
|
// 准备参数
|
||||||
|
|
Loading…
Reference in New Issue