修改经办段统一门户登录
This commit is contained in:
@@ -1,7 +1,10 @@
|
|||||||
package com.ruoyi.cms.util.oauth;
|
package com.ruoyi.cms.util.oauth;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONArray;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
import com.alibaba.fastjson2.TypeReference;
|
import com.alibaba.fastjson2.TypeReference;
|
||||||
|
import com.ruoyi.common.core.domain.entity.tymh.authority.QxUserRole;
|
||||||
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwTokenResult;
|
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwTokenResult;
|
||||||
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwUserInfoResult;
|
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwUserInfoResult;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
@@ -11,6 +14,7 @@ import org.springframework.stereotype.Component;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -24,53 +28,38 @@ public class OauthClient {
|
|||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(OauthClient.class);
|
private static final Logger log = LoggerFactory.getLogger(OauthClient.class);
|
||||||
/*====================== 内网 ======================*/
|
/*====================== 内网 ======================*/
|
||||||
// 网关请求-内网获取token
|
|
||||||
@Value("${oauth.usptnw.nwGatewayGetTokenUrl}")
|
@Value("${oauth.usptnw.nwGatewayGetTokenUrl}")
|
||||||
private String nwGatewayGetTokenUrl;
|
private String nwGatewayGetTokenUrl;
|
||||||
// 网关请求-内网获取用户信息
|
|
||||||
@Value("${oauth.usptnw.nwGatewayGetUserInfoUrl}")
|
@Value("${oauth.usptnw.nwGatewayGetUserInfoUrl}")
|
||||||
private String nwGatewayGetUserInfoUrl;
|
private String nwGatewayGetUserInfoUrl;
|
||||||
|
|
||||||
/*====================== 外网 ======================*/
|
/*====================== 外网 ======================*/
|
||||||
//post-外网注册地址
|
|
||||||
@Value("${oauth.usptww.wwRegisterPostUrl}")
|
@Value("${oauth.usptww.wwRegisterPostUrl}")
|
||||||
private String wwRegisterPostUrl;
|
private String wwRegisterPostUrl;
|
||||||
// post-外网获取token
|
|
||||||
@Value("${oauth.usptww.wwTokenPostUrl}")
|
@Value("${oauth.usptww.wwTokenPostUrl}")
|
||||||
private String wwTokenPostUrl;
|
private String wwTokenPostUrl;
|
||||||
//post-外网获取用户信息
|
|
||||||
@Value("${oauth.usptww.wwQueryWebPersonalInfoPostUrl}")
|
@Value("${oauth.usptww.wwQueryWebPersonalInfoPostUrl}")
|
||||||
private String wwQueryWebPersonalInfoPostUrl;
|
private String wwQueryWebPersonalInfoPostUrl;
|
||||||
//post-外网获取单位信息
|
|
||||||
@Value("${oauth.usptww.wwQueryWebEnterpriseInfoPostUrl}")
|
@Value("${oauth.usptww.wwQueryWebEnterpriseInfoPostUrl}")
|
||||||
private String wwQueryWebEnterpriseInfoPostUrl;
|
private String wwQueryWebEnterpriseInfoPostUrl;
|
||||||
|
|
||||||
/*====================== 统一门户 ======================*/
|
/*====================== 统一门户 ======================*/
|
||||||
//用户新增接口
|
|
||||||
@Value("${oauth.tyAddUserUrl}")
|
@Value("${oauth.tyAddUserUrl}")
|
||||||
private String tyAddUserUrl;
|
private String tyAddUserUrl;
|
||||||
//获取当前用户有权系统列表
|
|
||||||
@Value("${oauth.tyQueryUserSysListUrl}")
|
@Value("${oauth.tyQueryUserSysListUrl}")
|
||||||
private String tyQueryUserSysListUrl;
|
private String tyQueryUserSysListUrl;
|
||||||
//获取当前用户有权角色列表
|
|
||||||
@Value("${oauth.tyQueryUserRoleListUrl}")
|
@Value("${oauth.tyQueryUserRoleListUrl}")
|
||||||
private String tyQueryUserRoleListUrl;
|
private String tyQueryUserRoleListUrl;
|
||||||
//获取角色功能权限信息
|
|
||||||
@Value("${oauth.tyQueryRoleInfoUrl}")
|
@Value("${oauth.tyQueryRoleInfoUrl}")
|
||||||
private String tyQueryRoleInfoUrl;
|
private String tyQueryRoleInfoUrl;
|
||||||
//获取用户详细信息
|
|
||||||
@Value("${oauth.tyQueryUserInfo}")
|
@Value("${oauth.tyQueryUserInfo}")
|
||||||
private String tyQueryUserInfo;
|
private String tyQueryUserInfo;
|
||||||
//获取机构详细信息
|
|
||||||
@Value("${oauth.tyQueryUnitInfo}")
|
@Value("${oauth.tyQueryUnitInfo}")
|
||||||
private String tyQueryUnitInfo;
|
private String tyQueryUnitInfo;
|
||||||
//客户端id
|
|
||||||
@Value("${oauth.appid}")
|
@Value("${oauth.appid}")
|
||||||
private String appid;
|
private String appid;
|
||||||
//授权码
|
|
||||||
@Value("${oauth.clientsecretkey}")
|
@Value("${oauth.clientsecretkey}")
|
||||||
private String clientsecretkey;
|
private String clientsecretkey;
|
||||||
// 超时配置
|
|
||||||
@Value("${oauth.connect-timeout:10}")
|
@Value("${oauth.connect-timeout:10}")
|
||||||
private int connectTimeout;
|
private int connectTimeout;
|
||||||
@Value("${oauth.read-timeout:30}")
|
@Value("${oauth.read-timeout:30}")
|
||||||
@@ -80,7 +69,6 @@ public class OauthClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取经办段token
|
* 获取经办段token
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public NwTokenResult nwGetToken(String code) throws IOException, TimeoutException {
|
public NwTokenResult nwGetToken(String code) throws IOException, TimeoutException {
|
||||||
if (StringUtils.isEmpty(code)) {
|
if (StringUtils.isEmpty(code)) {
|
||||||
@@ -119,7 +107,6 @@ public class OauthClient {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取经办段用户id
|
* 获取经办段用户id
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
public NwUserInfoResult nwGetUserInfo(String accessToken) throws IOException, TimeoutException {
|
public NwUserInfoResult nwGetUserInfo(String accessToken) throws IOException, TimeoutException {
|
||||||
Map<String, Object> params = new HashMap<>(2);
|
Map<String, Object> params = new HashMap<>(2);
|
||||||
@@ -134,120 +121,177 @@ public class OauthClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据用户id查询用户角色列表
|
||||||
|
* @param userid
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
* @throws TimeoutException
|
||||||
|
*/
|
||||||
|
public List<QxUserRole> getUserRoleList(Long userid) throws IOException, TimeoutException {
|
||||||
|
Map<String, Object> params = new HashMap<>(2);
|
||||||
|
params.put("appid", appid);
|
||||||
|
params.put("userid", String.valueOf(userid));
|
||||||
|
|
||||||
|
return executePostRequestResultList(
|
||||||
|
tyQueryUserRoleListUrl,
|
||||||
|
params,
|
||||||
|
QxUserRole.class,
|
||||||
|
"根据用户id获取用户角色列表"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 公共POST请求执行方法
|
* 公共POST请求执行方法
|
||||||
* @param url 请求URL
|
|
||||||
* @param params 请求参数
|
|
||||||
* @param typeReference 响应类型引用
|
|
||||||
* @param operationName 操作名称(用于日志和异常信息)
|
|
||||||
* @return 响应数据对象
|
|
||||||
*/
|
*/
|
||||||
private <T> T executePostRequest(String url, Map<String, Object> params,
|
private <T> T executePostRequest(String url, Map<String, Object> params,
|
||||||
TypeReference<Response<T>> typeReference, String operationName)
|
TypeReference<Response<T>> typeReference, String operationName)
|
||||||
throws IOException, TimeoutException {
|
throws IOException, TimeoutException {
|
||||||
String responseJson = null;
|
String responseJson = HttpUtils.doPostJson(
|
||||||
try {
|
|
||||||
responseJson = HttpUtils.doPostJson(
|
|
||||||
url,
|
url,
|
||||||
params,
|
params,
|
||||||
connectTimeout,
|
connectTimeout,
|
||||||
readTimeout,
|
readTimeout,
|
||||||
writeTimeout
|
writeTimeout
|
||||||
);
|
);
|
||||||
}catch (Exception e){
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return validateResponse(responseJson, operationName, typeReference);
|
return validateResponse(responseJson, operationName, typeReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 公共响应校验工具方法(网关响应 + 业务 errflag 校验)
|
* 公共POST请求执行方法处理List
|
||||||
|
*/
|
||||||
|
private <T> List<T> executePostRequestResultList(String url, Map<String, Object> params,
|
||||||
|
Class<T> clazz, String operationName)
|
||||||
|
throws IOException, TimeoutException {
|
||||||
|
String responseJson = HttpUtils.doPostJson(
|
||||||
|
url,
|
||||||
|
params,
|
||||||
|
connectTimeout,
|
||||||
|
readTimeout,
|
||||||
|
writeTimeout
|
||||||
|
);
|
||||||
|
return parseMapOrDataArray(responseJson, operationName, clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 简化后的响应校验方法(已移除网关返回码判断)
|
||||||
*/
|
*/
|
||||||
private <T> T validateResponse(String responseJson, String operationName, TypeReference<Response<T>> typeReference) {
|
private <T> T validateResponse(String responseJson, String operationName, TypeReference<Response<T>> typeReference) {
|
||||||
// 1. 校验响应是否为空
|
// 1. 校验响应空值
|
||||||
if (StringUtils.isEmpty(responseJson)) {
|
if (StringUtils.isEmpty(responseJson)) {
|
||||||
String errorMsg = operationName + "失败:接口返回空响应";
|
String errorMsg = operationName + "失败:接口返回空";
|
||||||
log.error(errorMsg);
|
log.error(errorMsg);
|
||||||
throw new BusinessException("EMPTY_RESPONSE", errorMsg);
|
throw new RuntimeException(errorMsg);
|
||||||
}
|
}
|
||||||
log.debug("{}接口返回原始数据: {}", operationName, responseJson);
|
log.debug("{}返回数据: {}", operationName, responseJson);
|
||||||
|
|
||||||
// 2. 解析网关响应(外层 appcode 校验)
|
// 2. 解析响应并校验基础格式
|
||||||
Response<T> gatewayResponse = JSON.parseObject(responseJson, typeReference);
|
Response<T> gatewayResponse = JSON.parseObject(responseJson, typeReference);
|
||||||
if (gatewayResponse == null) {
|
if (gatewayResponse == null) {
|
||||||
String errorMsg = operationName + "失败:网关响应格式异常(无法解析)";
|
String errorMsg = operationName + "失败:响应格式错误";
|
||||||
log.error("{} | 原始响应: {}", errorMsg, responseJson);
|
log.error("{} | 原始响应: {}", errorMsg, responseJson);
|
||||||
throw new BusinessException("GATEWAY_PARSE_ERROR", errorMsg);
|
throw new RuntimeException(errorMsg);
|
||||||
}
|
|
||||||
|
|
||||||
if (!"0".equals(gatewayResponse.getAppcode())) {
|
|
||||||
String errorMsg = String.format("%s失败:网关响应失败 | appcode: %s, msg: %s",
|
|
||||||
operationName, gatewayResponse.getAppcode(), gatewayResponse.getMsg());
|
|
||||||
log.error("{} | 原始响应: {}", errorMsg, responseJson);
|
|
||||||
throw new BusinessException(gatewayResponse.getAppcode(), errorMsg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3. 校验业务数据(移除了网关appcode的判断逻辑)
|
||||||
T data = gatewayResponse.getData();
|
T data = gatewayResponse.getData();
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
String errorMsg = operationName + "失败:响应data字段为空";
|
String errorMsg = operationName + "失败:业务数据为空";
|
||||||
log.error("{} | 原始响应: {}", errorMsg, responseJson);
|
log.error("{} | 原始响应: {}", errorMsg, responseJson);
|
||||||
throw new BusinessException("DATA_EMPTY", errorMsg);
|
throw new RuntimeException(errorMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data instanceof ErrFlagResponse) {
|
|
||||||
ErrFlagResponse errFlagResponse = (ErrFlagResponse) data;
|
|
||||||
if (!errFlagResponse.isSuccess()) {
|
|
||||||
String errorMsg = String.format("%s失败:%s(错误标识:%s)",
|
|
||||||
operationName, errFlagResponse.getErrtext(), errFlagResponse.getErrflag());
|
|
||||||
log.error("{} | 原始响应: {}", errorMsg, responseJson);
|
|
||||||
throw new BusinessException(errFlagResponse.getErrflag(), errorMsg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 6. 所有校验通过,返回业务数据
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 解析List
|
||||||
|
* @param jsonStr
|
||||||
|
* @param clazz
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> List<T> parseMapOrDataArray(String jsonStr, String operationName, Class<T> clazz) {
|
||||||
|
if (StringUtils.isEmpty(jsonStr)) {
|
||||||
|
String errorMsg = operationName + "失败:接口返回空";
|
||||||
|
log.error(errorMsg);
|
||||||
|
throw new RuntimeException(errorMsg);
|
||||||
|
}
|
||||||
|
JSONObject jsonObject;
|
||||||
|
try {
|
||||||
|
jsonObject = JSON.parseObject(jsonStr);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String errorMsg = operationName + "失败:响应格式错误(非合法 JSON)";
|
||||||
|
log.error("{} | 原始响应: {}", errorMsg, jsonStr, e);
|
||||||
|
throw new RuntimeException(errorMsg, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jsonObject == null) {
|
||||||
|
String errorMsg = operationName + "失败:响应格式错误(解析后为 null)";
|
||||||
|
log.error("{} | 原始响应: {}", errorMsg, jsonStr);
|
||||||
|
throw new RuntimeException(errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSONArray targetArray = getJSONArraySafe(jsonObject, "map");
|
||||||
|
if (targetArray == null || targetArray.isEmpty()) {
|
||||||
|
targetArray = getJSONArraySafe(jsonObject, "data");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetArray == null || targetArray.isEmpty()) {
|
||||||
|
String errorMsg = operationName + "失败:业务数据为空(map/data 字段无有效数组)";
|
||||||
|
log.error("{} | 原始响应: {}", errorMsg, jsonStr);
|
||||||
|
throw new RuntimeException(errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<T> dataList;
|
||||||
|
try {
|
||||||
|
dataList = JSON.parseArray(targetArray.toJSONString(), clazz);
|
||||||
|
} catch (Exception e) {
|
||||||
|
String errorMsg = operationName + "失败:数据解析失败(数组元素与目标类不匹配)";
|
||||||
|
log.error("{} | 原始响应: {} | 目标类: {}", errorMsg, jsonStr, clazz.getName(), e);
|
||||||
|
throw new RuntimeException(errorMsg, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataList == null || dataList.isEmpty()) {
|
||||||
|
String errorMsg = operationName + "失败:解析后业务数据为空";
|
||||||
|
log.error("{} | 原始响应: {}", errorMsg, jsonStr);
|
||||||
|
throw new RuntimeException(errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 避免空值和类型转换异常
|
||||||
|
* @param jsonObject
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private static JSONArray getJSONArraySafe(JSONObject jsonObject, String key) {
|
||||||
|
if (jsonObject == null || StringUtils.isEmpty(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!jsonObject.containsKey(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Object value = jsonObject.get(key);
|
||||||
|
return (value instanceof JSONArray) ? (JSONArray) value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 静态返回解析
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
public static class Response<T> {
|
public static class Response<T> {
|
||||||
private String appcode;
|
private String appcode;
|
||||||
private String code;
|
|
||||||
private String msg;
|
private String msg;
|
||||||
private T data;
|
private T data;
|
||||||
private Object map;
|
|
||||||
|
|
||||||
// Getter(仅保留需要的字段,setter可选)
|
|
||||||
public String getAppcode() { return appcode; }
|
public String getAppcode() { return appcode; }
|
||||||
public String getMsg() { return msg; }
|
public String getMsg() { return msg; }
|
||||||
public T getData() { return data; }
|
public T getData() { return data; }
|
||||||
}
|
|
||||||
|
|
||||||
public class BusinessException extends RuntimeException {
|
public void setAppcode(String appcode) { this.appcode = appcode; }
|
||||||
private String code; // 错误码(可关联门户错误码)
|
public void setMsg(String msg) { this.msg = msg; }
|
||||||
|
public void setData(T data) { this.data = data; }
|
||||||
public BusinessException(String message) {
|
|
||||||
super(message);
|
|
||||||
this.code = "BUSINESS_ERROR";
|
|
||||||
}
|
|
||||||
|
|
||||||
public BusinessException(String code, String message) {
|
|
||||||
super(message);
|
|
||||||
this.code = code;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getter
|
|
||||||
public String getCode() {
|
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ErrFlagResponse {
|
|
||||||
String getErrflag();
|
|
||||||
String getErrtext();
|
|
||||||
|
|
||||||
// 默认方法:判断是否成功(0=成功,1=失败)
|
|
||||||
default boolean isSuccess() {
|
|
||||||
return "0".equals(getErrflag());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package com.ruoyi.common.core.domain.entity.tymh.authority;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户角色
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class QxUserRole {
|
||||||
|
private Long roleId;
|
||||||
|
private String roleName;
|
||||||
|
private String roleType;
|
||||||
|
private String appId;
|
||||||
|
private String roleLevel;
|
||||||
|
private String aae100;
|
||||||
|
private String aae011;
|
||||||
|
private String postType;
|
||||||
|
private String agf001;
|
||||||
|
private String aae036;
|
||||||
|
private String agf003;
|
||||||
|
private String agf002;
|
||||||
|
private String agf004;
|
||||||
|
private String folderId;
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.ruoyi.common.core.domain.entity.tymh.nwToken;
|
package com.ruoyi.common.core.domain.entity.tymh.nwToken;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.alibaba.fastjson2.annotation.JSONField;
|
||||||
import io.swagger.annotations.ApiModelProperty;
|
import io.swagger.annotations.ApiModelProperty;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -13,10 +13,11 @@ public class NwTokenResult {
|
|||||||
@ApiModelProperty("错误文本")
|
@ApiModelProperty("错误文本")
|
||||||
private String errtext;
|
private String errtext;
|
||||||
|
|
||||||
@JsonProperty("Access-Token")
|
@JSONField(name = "access_token")
|
||||||
@ApiModelProperty("访问令牌")
|
@ApiModelProperty("访问令牌")
|
||||||
private String accessToken;
|
private String accessToken;
|
||||||
|
|
||||||
|
@JSONField(name = "expires_in")
|
||||||
@ApiModelProperty("access_token接口调用凭证超")
|
@ApiModelProperty("access_token接口调用凭证超")
|
||||||
private Long expiresIn;
|
private Long expiresIn;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.ruoyi.framework.web.service;
|
|||||||
import com.ruoyi.cms.util.oauth.OauthClient;
|
import com.ruoyi.cms.util.oauth.OauthClient;
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||||
|
import com.ruoyi.common.core.domain.entity.tymh.authority.QxUserRole;
|
||||||
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwTokenResult;
|
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwTokenResult;
|
||||||
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwUserInfoResult;
|
import com.ruoyi.common.core.domain.entity.tymh.nwToken.NwUserInfoResult;
|
||||||
import com.ruoyi.common.core.domain.entity.tymh.nwToken.PortalTokenCacheDTO;
|
import com.ruoyi.common.core.domain.entity.tymh.nwToken.PortalTokenCacheDTO;
|
||||||
@@ -19,15 +20,18 @@ import com.ruoyi.framework.manager.factory.AsyncFactory;
|
|||||||
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
|
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
|
||||||
import com.ruoyi.system.service.ISysUserService;
|
import com.ruoyi.system.service.ISysUserService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class OauthLoginService {
|
public class OauthLoginService {
|
||||||
@@ -42,7 +46,7 @@ public class OauthLoginService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ISysUserService sysUserService;
|
private ISysUserService sysUserService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private AuthenticationManager authenticationManager;
|
private UserDetailsService userDetailsService;
|
||||||
// Redis缓存:门户UserID → 若依本地用户名(避免重复匹配数据库)
|
// Redis缓存:门户UserID → 若依本地用户名(避免重复匹配数据库)
|
||||||
private static final String REDIS_KEY_PORTAL_USER_MAPPING = "portal:user:mapping:";
|
private static final String REDIS_KEY_PORTAL_USER_MAPPING = "portal:user:mapping:";
|
||||||
// 门户 Token 存储前缀(Redis 键:门户 userId → 门户 Token 信息)
|
// 门户 Token 存储前缀(Redis 键:门户 userId → 门户 Token 信息)
|
||||||
@@ -92,6 +96,12 @@ public class OauthLoginService {
|
|||||||
String cacheKey = REDIS_KEY_PORTAL_USER_MAPPING + portalUserId;
|
String cacheKey = REDIS_KEY_PORTAL_USER_MAPPING + portalUserId;
|
||||||
String localUsername = redisCache.getCacheObject(cacheKey);
|
String localUsername = redisCache.getCacheObject(cacheKey);
|
||||||
if (StringUtils.isNotBlank(localUsername)) {
|
if (StringUtils.isNotBlank(localUsername)) {
|
||||||
|
try {
|
||||||
|
//更新用户信息
|
||||||
|
//updateUserInfo(portalUser);
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
return localUsername;
|
return localUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,9 +144,20 @@ public class OauthLoginService {
|
|||||||
newUser.setUserId(portalUserId);
|
newUser.setUserId(portalUserId);
|
||||||
newUser.setPassword(SecurityUtils.encryptPassword("123456"));
|
newUser.setPassword(SecurityUtils.encryptPassword("123456"));
|
||||||
newUser.setDelFlag("0");
|
newUser.setDelFlag("0");
|
||||||
|
try {
|
||||||
|
//查询权限,保存权限
|
||||||
|
List<QxUserRole> userRoleList=oauthClient.getUserRoleList(portalUserId);
|
||||||
|
if(userRoleList!=null&&userRoleList.size()>0){
|
||||||
|
Long[] longs=userRoleList.stream().mapToLong(QxUserRole::getRoleId).boxed().toArray(Long[]::new);;
|
||||||
|
newUser.setRoleIds(longs);
|
||||||
|
}else {
|
||||||
|
throw new Exception("未查询到用户角色,请授权后访问!");
|
||||||
|
}
|
||||||
// 调用若依原生方法新增用户(自动处理角色关联,需提前配置默认角色)
|
// 调用若依原生方法新增用户(自动处理角色关联,需提前配置默认角色)
|
||||||
sysUserService.insertUser(newUser);
|
sysUserService.insertUser(newUser);
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
return newUser;
|
return newUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,15 +168,16 @@ public class OauthLoginService {
|
|||||||
private Authentication authenticateLocalUser(String localUsername) {
|
private Authentication authenticateLocalUser(String localUsername) {
|
||||||
Authentication authentication = null;
|
Authentication authentication = null;
|
||||||
try {
|
try {
|
||||||
// 构建认证令牌:用户名+空密码(因为门户已验证身份,本地仅需加载用户信息)
|
UserDetails userDetails = userDetailsService.loadUserByUsername(localUsername);
|
||||||
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(localUsername, "");
|
|
||||||
AuthenticationContextHolder.setContext(authenticationToken);
|
|
||||||
|
|
||||||
// 触发认证:会调用 UserDetailsServiceImpl.loadUserByUsername(localUsername)
|
authentication = new UsernamePasswordAuthenticationToken(
|
||||||
// 该方法会加载用户权限、角色,返回 LoginUser
|
userDetails,
|
||||||
authentication = authenticationManager.authenticate(authenticationToken);
|
null, // 密码为 null,彻底绕过 Spring Security 的密码校验
|
||||||
|
userDetails.getAuthorities()
|
||||||
|
);
|
||||||
|
|
||||||
|
AuthenticationContextHolder.setContext(authentication);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// 捕获认证异常(如用户被禁用、权限加载失败等)
|
|
||||||
throw new ServiceException("本地用户认证失败:" + e.getMessage());
|
throw new ServiceException("本地用户认证失败:" + e.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
AuthenticationContextHolder.clearContext();
|
AuthenticationContextHolder.clearContext();
|
||||||
@@ -178,6 +200,34 @@ public class OauthLoginService {
|
|||||||
redisCache.setCacheObject(redisKey, tokenCache, safeLongToInt(tokenResult.getExpiresIn()), TimeUnit.SECONDS);
|
redisCache.setCacheObject(redisKey, tokenCache, safeLongToInt(tokenResult.getExpiresIn()), TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改用户信息
|
||||||
|
* @param portalUser
|
||||||
|
*/
|
||||||
|
private void updateUserInfo(NwUserInfoResult portalUser){
|
||||||
|
SysUser sysUser=new SysUser();
|
||||||
|
Long portalUserId=parsePortalUserId(portalUser.getUserid());
|
||||||
|
//查询用户角色
|
||||||
|
try {
|
||||||
|
List<QxUserRole> userRoleList=oauthClient.getUserRoleList(portalUserId);
|
||||||
|
if(userRoleList!=null&&userRoleList.size()>0){
|
||||||
|
Long[] longs=userRoleList.stream().mapToLong(QxUserRole::getRoleId).boxed().toArray(Long[]::new);;
|
||||||
|
sysUser.setRoleIds(longs);
|
||||||
|
}else {
|
||||||
|
throw new Exception("未查询到用户角色,请授权后访问!");
|
||||||
|
}
|
||||||
|
}catch (Exception e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
String localUsername = "portal_" + portalUserId;
|
||||||
|
sysUser.setUserName(localUsername);
|
||||||
|
sysUser.setNickName(portalUser.getName());
|
||||||
|
sysUser.setIdCard(portalUser.getIdcardno());
|
||||||
|
sysUser.setUserId(portalUserId);
|
||||||
|
sysUserService.updateUser(sysUser);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 记录登录信息(复用若依原生逻辑,直接复制过来)
|
* 记录登录信息(复用若依原生逻辑,直接复制过来)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ public class UserDetailsServiceImpl implements UserDetailsService
|
|||||||
log.info("登录用户:{} 已被停用.", username);
|
log.info("登录用户:{} 已被停用.", username);
|
||||||
throw new ServiceException(MessageUtils.message("user.blocked"));
|
throw new ServiceException(MessageUtils.message("user.blocked"));
|
||||||
}
|
}
|
||||||
|
////单点跳过验证密码阶段
|
||||||
passwordService.validate(user);
|
//passwordService.validate(user);
|
||||||
|
|
||||||
return createLoginUser(user);
|
return createLoginUser(user);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user