Commit 14894580 by mahx

同步现场腾讯获取用户接口

parent 160c2fe1
...@@ -44,17 +44,43 @@ public class RESTLogoutSuccessHandler implements LogoutSuccessHandler { ...@@ -44,17 +44,43 @@ public class RESTLogoutSuccessHandler implements LogoutSuccessHandler {
Cookie[] cookies = request.getCookies(); Cookie[] cookies = request.getCookies();
if (cookies != null) { if (cookies != null) {
for (Cookie cookie : cookies) { for (Cookie cookie : cookies) {
cookie.setValue(""); clearCookie(request, response, cookie.getName(), cookie.getPath(), cookie.getDomain());
cookie.setPath(getCookiePath(request));
cookie.setMaxAge(0);
response.addCookie(cookie);
} }
} }
} }
private String getCookiePath(HttpServletRequest request) { /**
* 清除指定 cookie,尝试多个路径和 domain 组合确保清除成功
*/
private void clearCookie(HttpServletRequest request, HttpServletResponse response, String cookieName, String cookiePath, String cookieDomain) {
String contextPath = request.getContextPath(); String contextPath = request.getContextPath();
return contextPath != null && !contextPath.isEmpty() ? contextPath : "/"; String[] paths = {cookiePath, contextPath, contextPath + "/", "/", null};
for (String path : paths) {
if (path == null || path.isEmpty()) {
path = "/";
}
clearCookieWithPathAndDomain(request, response, cookieName, path, null);
clearCookieWithPathAndDomain(request, response, cookieName, path, "");
}
}
/**
* 使用指定路径和 domain 清除 cookie
*/
private void clearCookieWithPathAndDomain(HttpServletRequest request, HttpServletResponse response, String name, String path, String domain) {
try {
Cookie cookie = new Cookie(name, "");
cookie.setPath(path);
cookie.setMaxAge(0);
if (domain != null && !domain.isEmpty()) {
cookie.setDomain(domain);
}
cookie.setHttpOnly(true);
cookie.setSecure(request.isSecure());
response.addCookie(cookie);
} catch (Exception ignored) {
}
} }
} }
\ No newline at end of file
...@@ -3,6 +3,8 @@ package com.keymobile.sso.service; ...@@ -3,6 +3,8 @@ package com.keymobile.sso.service;
import org.springframework.cloud.openfeign.FeignClient; import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import com.keymobile.authservice.common.UserGroup;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -12,8 +14,39 @@ public interface AuthService { ...@@ -12,8 +14,39 @@ public interface AuthService {
@RequestMapping(value = "/users/findByName") @RequestMapping(value = "/users/findByName")
List<Map<String, Object>> getUserByName(@RequestParam(value = "match") String match); List<Map<String, Object>> getUserByName(@RequestParam(value = "match") String match);
@RequestMapping(value = "/users/{userId}", method = RequestMethod.GET)
Map<String, Object> getUserByUserId(@PathVariable(value = "userId") Long userId);
@PostMapping(value = "/users") @PostMapping(value = "/users")
Map<String, Object> addUser(@RequestBody Map<String, Object> user); Map<String, Object> addUser(@RequestBody Map<String, Object> user);
@RequestMapping(value = "/users", method = RequestMethod.GET)
List<Map<String, Object>> getAllUsers(@RequestParam(value = "types", required = false) String[] types);
//添加用户组
@PostMapping(value = "/userGroups")
Map<String, Object> addUserGroup(@RequestBody Map<String, Object> userGroupAbstract);
//更新用户组
@PostMapping(value = "/userGroups/{userGroupId}")
Map<String, Object> updateUserGroup(@PathVariable(value = "userGroupId") Long userGroupId,
@RequestBody Map<String, Object> userGroupAbstract);
//查找用户组
@GetMapping("/userGroups/findByName")
List<Map<String, Object>> findUserGroupsByName(@RequestParam(value = "match", required = false) String match);
@RequestMapping(value = "/userGroups", method = RequestMethod.GET)
List<Map<String, Object>> findAllUserGroups();
//将用户加入用户组
@PostMapping("/userGroups/{userGroupId}/users")
Map<String, Object> addUser(@PathVariable(value = "userGroupId") Long userGroupId,
@RequestParam(value = "userIds", required = true) Long[] userIds);
//根据用户组ID获取用户组
@GetMapping("/userGroups/{userGroupId}")
Map<String, Object> getUserGroupById(@PathVariable(value = "userGroupId") Long userGroupId);
} }
package com.keymobile.sso.ud;
import com.keymobile.sso.ud.api.*;
import com.keymobile.sso.ud.config.ApiConfig;
import com.keymobile.sso.ud.util.HttpClient;
import com.google.gson.Gson;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.List;
/**
* API测试运行入口类
*/
public class ApiTestRunner {
private static final Logger logger = LoggerFactory.getLogger(ApiTestRunner.class);
private static ApiConfig config;
static {
config = new ApiConfig(
"964a5eb6c336475caf9a9830d0ee357d",
"fb7f49a789bd473681bdafef5770907a",
"portal-udadmin.sznsmic.com",
"dfaaad6a-87f2-419b-98d0-9a950be8e479"
);
}
public static void main(String[] args) {
try {
logger.info("\n\n\n========== 用户机构获取接口测试 ==========\n\n\n");
//testDescribeOrganizationList();
//testSortOrganization();
//testDescribeOrganization();
logger.info("\n\n\n========== 用户部门获取接口测试 ==========\n\n\n");
//testDescribeDepartmentList();
//testDescribeDepartment();
logger.info("\n\n\n========== 用户接口测试 ==========\n\n\n");
//testDescribeUser();
//testDescribeUsersByOrganization();
logger.info("\n\n\n========== 用户组接口测试 ==========\n\n\n");
testDescribeGroupList();
//testDescribeGroup();
//testDescribeGroupUserList();
logger.info("\n\n\n========== 所有测试完成 ==========\n\n\n");
} catch (Exception e) {
logger.error("测试执行失败", e);
}
}
/**
* 测试获取认证域下所有机构列表
*/
private static void testDescribeOrganizationList() throws Exception {
logger.info("========== 测试: 获取认证域下所有机构列表 ==========");
OrganizationApi api = new OrganizationApi(config);
OrganizationApi.DescribeOrganizationListResponse response = api.describeOrganizationList();
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
logger.info("机构数量: {}", response.getData() != null ? response.getData().size() : 0);
if (response.getData() != null) {
for (OrganizationApi.Organization org : response.getData()) {
logger.info("机构: {} - {}", org.getOrgId(), org.getDisplayName());
}
}
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
/**
* 测试机构排序
*/
private static void testSortOrganization() throws Exception {
logger.info("========== 测试: 机构排序 ==========");
OrganizationApi api = new OrganizationApi(config);
List<String> orgIdList = Arrays.asList(
"6d26ca90-d9cb-4026-a8ab-14c341062a2d",
"c02a06ef-ac68-457a-8b97-3217b390d8f1"
);
OrganizationApi.SortOrganizationResponse response = api.sortOrganization(orgIdList);
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
/**
* 测试获取机构信息
*/
private static void testDescribeOrganization() throws Exception {
logger.info("========== 测试: 获取机构信息 ==========");
OrganizationApi api = new OrganizationApi(config);
String orgId = "c02a06ef-ac68-457a-8b97-3217b390d8f1";
OrganizationApi.DescribeOrganizationResponse response = api.describeOrganization(orgId);
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
OrganizationApi.Organization org = response.getData();
if (org != null) {
logger.info("机构信息:");
logger.info(" - OrgId: {}", org.getOrgId());
logger.info(" - DisplayName: {}", org.getDisplayName());
logger.info(" - Description: {}", org.getDescription());
logger.info(" - DefaultRootOrg: {}", org.getDefaultRootOrg());
logger.info(" - UserTotal: {}", org.getUserTotal());
}
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
/**
* 测试获取部门列表
*/
private static void testDescribeDepartmentList() throws Exception {
logger.info("========== 测试: 获取部门列表 ==========");
DepartmentApi api = new DepartmentApi(config);
DepartmentApi.DescribeDepartmentListResponse response =
api.describeDepartmentListByOrgIdList(
Arrays.asList("c02a06ef-ac68-457a-8b97-3217b390d8f1"));
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
logger.info("部门数量: {}", response.getData() != null ? response.getData().size() : 0);
if (response.getData() != null) {
for (DepartmentApi.Department dept : response.getData()) {
logger.info("部门: {} - {}", dept.getDepartmentId(), dept.getDisplayName());
}
}
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
/**
* 测试获取部门信息
*/
private static void testDescribeDepartment() throws Exception {
logger.info("========== 测试: 获取部门信息 ==========");
DepartmentApi api = new DepartmentApi(config);
String departmentId = "c02a06ef-ac68-457a-8b97-3217b390d8f1";
DepartmentApi.DescribeDepartmentResponse response = api.describeDepartment(departmentId);
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
DepartmentApi.Department dept = response.getData();
if (dept != null) {
logger.info("部门信息:");
logger.info(" - DepartmentId: {}", dept.getDepartmentId());
logger.info(" - DisplayName: {}", dept.getDisplayName());
logger.info(" - ParentOrgId: {}", dept.getParentOrgId());
logger.info(" - ParentOrgDisplayName: {}", dept.getParentOrgDisplayName());
logger.info(" - UserTotal: {}", dept.getUserTotal());
}
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
/**
* 测试查询用户
*/
private static void testDescribeUser() throws Exception {
logger.info("========== 测试: 查询用户 ==========");
UserApi api = new UserApi(config);
String userId = "8fa4b2bd-32af-4af9-a530-84fd3abc0bea";
UserApi.DescribeUserResponse response = api.describeUserById(null);
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
UserApi.User user = response.getData();
if (user != null) {
logger.info("用户信息:");
logger.info(" - UserId: {}", user.getUserId());
logger.info(" - DisplayName: {}", user.getDisplayName());
logger.info(" - UserName: {}", user.getUsername());
logger.info(" - Email: {}", user.getEmail());
logger.info(" - Phone: {}", user.getPhone());
logger.info(" - UserType: {}", user.getUserType());
logger.info(" - Status: {}", user.getStatus());
}
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
/**
* 测试获取用户组列表
*/
private static void testDescribeGroupList() throws Exception {
logger.info("========== 测试: 获取用户组列表 ==========");
GroupApi api = new GroupApi(config);
GroupApi.DescribeGroupListResponse response = api.describeGroupList(null, 1L, 10L);
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
logger.info("用户组数量: {}", response.getData() != null ? response.getData().size() : 0);
logger.info("总数量: {}", response.getTotal());
logger.info("页码: {}", response.getPageNumber());
logger.info("每页大小: {}", response.getPageSize());
if (response.getData() != null) {
for (GroupApi.Group group : response.getData()) {
logger.info("用户组: {} - {}", group.getGroupId(), group.getDisplayName());
}
}
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
/**
* 测试获取用户组信息
*/
private static void testDescribeGroup() throws Exception {
logger.info("========== 测试: 获取用户组信息 ==========");
GroupApi api = new GroupApi(config);
String groupId = "5e37f3ba-1011-41f2-96e3-e0b5a8631380";
GroupApi.DescribeGroupResponse response = api.describeGroup(groupId);
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
GroupApi.Group group = response.getData();
if (group != null) {
logger.info("用户组信息:");
logger.info(" - GroupId: {}", group.getGroupId());
logger.info(" - DisplayName: {}", group.getDisplayName());
logger.info(" - Description: {}", group.getDescription());
logger.info(" - OrgId: {}", group.getOrgId());
logger.info(" - UserTotal: {}", group.getUserTotal());
}
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
/**
* 测试获取用户组下的成员列表
*/
private static void testDescribeGroupUserList() throws Exception {
logger.info("========== 测试: 获取用户组下的成员列表 ==========");
GroupApi api = new GroupApi(config);
String groupId = "5e37f3ba-1011-41f2-96e3-e0b5a8631380";
GroupApi.DescribeGroupUserListResponse response = api.describeGroupUserList(groupId, null, null, 1L, 10L);
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
logger.info("成员数量: {}", response.getData() != null ? response.getData().size() : 0);
logger.info("总数量: {}", response.getTotal());
logger.info("页码: {}", response.getPageNumber());
logger.info("每页大小: {}", response.getPageSize());
if (response.getData() != null) {
for (GroupApi.GroupUser user : response.getData()) {
logger.info("成员: {} - {}", user.getUserId(), user.getDisplayName());
}
}
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
/**
* 测试查询部门下的用户
*/
private static void testDescribeUsersByOrganization() throws Exception {
logger.info("========== 测试: 查询部门下的用户 ==========");
UserApi api = new UserApi(config);
//String orgId = "c02a06ef-ac68-457a-8b97-3217b390d8f1";
//String orgId = "6d26ca90-d9cb-4026-a8ab-14c341062a2d";
//String orgId = "8d608b6f-2f6c-400d-b466-e244d6bcb970";
String orgId = "7de6b1ff-096b-41cb-b16f-b8c1110878a8";
UserApi.DescribeUsersByOrganizationResponse response = api.describeUsersByOrganization(orgId, null, null, 1L, 10L);
if (response.getResponse().isSuccess()) {
logger.info("请求成功! RequestId: {}", response.getResponse().getRequestId());
logger.info("用户数量: {}", response.getData() != null ? response.getData().size() : 0);
logger.info("总数量: {}", response.getTotal());
logger.info("页码: {}", response.getPageNumber());
logger.info("每页大小: {}", response.getPageSize());
if (response.getData() != null) {
for (UserApi.User user : response.getData()) {
logger.info("用户: {} - {}", user.getUserId(), user.getDisplayName());
}
}
} else {
logger.error("请求失败! Error: {} - {}",
response.getResponse().getError().getCode(),
response.getResponse().getError().getMessage());
}
logger.info("");
}
}
package com.keymobile.sso.ud;
import com.keymobile.sso.ud.util.TencentCloudSignV3;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
/**
* 签名验证测试类
* 使用腾讯云官方示例参数验证签名算法正确性
* 参考文档: https://cloud.tencent.com/document/product/628/45174
*/
public class SignVerificationTest {
public static void main(String[] args) throws Exception {
System.out.println("========== 腾讯云V3签名验证测试 ==========\n");
// 官方示例参数
String secretId = "AKID********************************";
String secretKey = "********************************";
String service = "cvm";
String host = "cvm.tencentcloudapi.com";
String action = "DescribeInstances";
String payload = "{\"Limit\": 1, \"Filters\": [{\"Values\": [\"\\u672a\\u547d\\u540d\"], \"Name\": \"instance-name\"}]}";
long timestamp = 1551113065; // 2019-02-25 08:44:25 UTC
// 官方预期签名
String expectedSignature = "10b1a37a7301a02ca19a647ad722d5e43b4b3cff309d421d85b46093f6ab6c4f";
String expectedAuthorization = "TC3-HMAC-SHA256 Credential=" + secretId + "/2019-02-25/cvm/tc3_request, SignedHeaders=content-type;host;x-tc-action, Signature=" + expectedSignature;
// 使用临时类来生成签名(使用cvm作为service)
TencentCloudSignV3 signer = new TencentCloudSignV3(secretId, secretKey, host) {
@Override
public String sign(String action, String payload, long timestamp) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(timestamp * 1000));
String hashedPayload = sha256Hex(payload);
String canonicalRequest = buildCanonicalRequest(action, hashedPayload);
String credentialScope = date + "/" + service + "/" + "tc3_request";
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = buildStringToSign(String.valueOf(timestamp), credentialScope, hashedCanonicalRequest);
String signature = calculateSignature(date, stringToSign);
return buildAuthorization(credentialScope, signature);
}
private String buildCanonicalRequest(String action, String hashedPayload) {
String httpRequestMethod = "POST";
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:application/json; charset=utf-8\n" +
"host:" + host + "\n" +
"x-tc-action:" + action.toLowerCase() + "\n";
String signedHeaders = "content-type;host;x-tc-action";
return httpRequestMethod + "\n" +
canonicalUri + "\n" +
canonicalQueryString + "\n" +
canonicalHeaders + "\n" +
signedHeaders + "\n" +
hashedPayload;
}
private String buildStringToSign(String timestamp, String credentialScope, String hashedCanonicalRequest) {
return "TC3-HMAC-SHA256" + "\n" +
timestamp + "\n" +
credentialScope + "\n" +
hashedCanonicalRequest;
}
private String calculateSignature(String date, String stringToSign) throws Exception {
byte[] secretDate = hmac256(("TC3" + secretKey).getBytes(StandardCharsets.UTF_8), date);
byte[] secretService = hmac256(secretDate, service);
byte[] secretSigning = hmac256(secretService, "tc3_request");
return bytesToHex(hmac256(secretSigning, stringToSign));
}
private String buildAuthorization(String credentialScope, String signature) {
String signedHeaders = "content-type;host;x-tc-action";
return "TC3-HMAC-SHA256" + " " +
"Credential=" + secretId + "/" + credentialScope + ", " +
"SignedHeaders=" + signedHeaders + ", " +
"Signature=" + signature;
}
private byte[] hmac256(byte[] key, String msg) throws Exception {
javax.crypto.Mac mac = javax.crypto.Mac.getInstance("HmacSHA256");
javax.crypto.spec.SecretKeySpec secretKeySpec = new javax.crypto.spec.SecretKeySpec(key, mac.getAlgorithm());
mac.init(secretKeySpec);
return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
}
private String sha256Hex(String s) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8));
return bytesToHex(d);
}
private String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
};
// 测试1: 生成签名
System.out.println("【测试1】使用官方示例参数验证签名");
System.out.println("SecretId: " + secretId);
System.out.println("SecretKey: " + secretKey);
System.out.println("Service: " + service);
System.out.println("Host: " + host);
System.out.println("Action: " + action);
System.out.println("Payload: " + payload);
System.out.println("Timestamp: " + timestamp);
System.out.println();
String signature = signer.sign(action, payload, timestamp);
System.out.println("生成的签名: " + signature);
System.out.println("预期签名: " + expectedAuthorization);
System.out.println("签名匹配: " + signature.equals(expectedAuthorization));
System.out.println();
// 测试2: 使用实际配置测试 (使用ApiTestRunner中的配置)
System.out.println("【测试2】使用实际配置生成签名");
String actualSecretId = "3822273eeb1a432a9041221b67f82979";
String actualSecretKey = "3ca5a9aeced9476dbe0ff8207b2363ca";
String actualHost = "portal-udadmin.sznsmic.com";
String actualAction = "DescribeOrganizationList";
String actualPayload = "{}";
long actualTimestamp = System.currentTimeMillis() / 1000;
TencentCloudSignV3 actualSigner = new TencentCloudSignV3(actualSecretId, actualSecretKey, actualHost);
String actualAuth = actualSigner.buildHeaders(actualAction, actualPayload, actualTimestamp).get("Authorization");
System.out.println("SecretId: " + actualSecretId);
System.out.println("Host: " + actualHost);
System.out.println("Action: " + actualAction);
System.out.println("Payload: " + actualPayload);
System.out.println("Timestamp: " + actualTimestamp);
System.out.println();
System.out.println("生成的Authorization:");
System.out.println(actualAuth);
System.out.println();
// 测试3: 生成curl命令
System.out.println("【测试3】生成curl命令");
String curlCommand = String.format(
"curl -X POST https://%s \\\n" +
"-H \"Authorization: %s\" \\\n" +
"-H \"Content-Type: application/json; charset=utf-8\" \\\n" +
"-H \"Host: %s\" \\\n" +
"-H \"X-TC-Action: %s\" \\\n" +
"-H \"X-TC-Timestamp: %d\" \\\n" +
"-H \"X-TC-Version: 2017-03-12\" \\\n" +
"-d '%s'",
actualHost, actualAuth, actualHost, actualAction, actualTimestamp, actualPayload
);
System.out.println(curlCommand);
System.out.println("\n========== 测试完成 ==========");
}
}
package com.keymobile.sso.ud.api;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.keymobile.sso.ud.api.common.BaseResponse;
import com.keymobile.sso.ud.config.ApiConfig;
import com.keymobile.sso.ud.util.HttpClient;
import com.keymobile.sso.ud.util.TencentCloudSignV3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* 部门API测试类
*/
public class DepartmentApi {
private static final Logger logger = LoggerFactory.getLogger(DepartmentApi.class);
private static final Gson gson = new Gson();
private final ApiConfig config;
private final TencentCloudSignV3 signer;
public DepartmentApi(ApiConfig config) {
this.config = config;
this.signer = new TencentCloudSignV3(config.getSecretId(), config.getSecretKey(), config.getHost());
}
/**
* 获取部门列表
*/
public DescribeDepartmentListResponse describeDepartmentList(DescribeDepartmentListRequest request) throws Exception {
String action = "DescribeDepartmentList";
String url = config.getBaseUrl() + "/auth/api/v1/DescribeDepartmentList";
String payload = gson.toJson(request);
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, DescribeDepartmentListResponse.class);
}
/**
* 获取部门列表 - 根据上级部门ID查询
*/
public DescribeDepartmentListResponse describeDepartmentListByParentId(String parentOrgId) throws Exception {
DescribeDepartmentListRequest request = new DescribeDepartmentListRequest();
SearchCondition searchCondition = new SearchCondition();
searchCondition.setParentOrgId(parentOrgId);
request.setSearchCondition(searchCondition);
return describeDepartmentList(request);
}
/**
* 获取部门列表 - 根据部门ID列表查询
*/
public DescribeDepartmentListResponse describeDepartmentListByOrgIdList(List<String> orgIdList) throws Exception {
DescribeDepartmentListRequest request = new DescribeDepartmentListRequest();
SearchCondition searchCondition = new SearchCondition();
searchCondition.setOrgIdList(orgIdList);
request.setSearchCondition(searchCondition);
return describeDepartmentList(request);
}
/**
* 获取部门列表 - 根据显示名称模糊搜索
*/
public DescribeDepartmentListResponse describeDepartmentListByDisplayName(String displayName) throws Exception {
DescribeDepartmentListRequest request = new DescribeDepartmentListRequest();
SearchCondition searchCondition = new SearchCondition();
searchCondition.setDisplayName(displayName);
request.setSearchCondition(searchCondition);
return describeDepartmentList(request);
}
/**
* 获取部门列表 - 根据显示名称和机构ID搜索
*/
public DescribeDepartmentListResponse describeDepartmentListByDisplayNameAndOrgId(String displayName, String orgId) throws Exception {
DescribeDepartmentListRequest request = new DescribeDepartmentListRequest();
SearchCondition searchCondition = new SearchCondition();
searchCondition.setDisplayName(displayName);
searchCondition.setOrgId(orgId);
request.setSearchCondition(searchCondition);
return describeDepartmentList(request);
}
/**
* 获取部门信息
*/
public DescribeDepartmentResponse describeDepartment(String departmentId) throws Exception {
String action = "DescribeDepartment";
String url = config.getBaseUrl() + "/auth/api/v1/DescribeDepartment";
Map<String, Object> params = new HashMap<>();
params.put("DepartmentId", departmentId);
String payload = gson.toJson(params);
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, DescribeDepartmentResponse.class);
}
/**
* 构建请求头
*/
private Map<String, String> buildHeaders(String action, String payload, long timestamp) throws Exception {
Map<String, String> headers = signer.buildHeaders(action, payload, timestamp);
headers.put("UdServiceId", config.getUdServiceId());
return headers;
}
// ==================== 请求类 ====================
/**
* DescribeDepartmentList 请求
*/
public static class DescribeDepartmentListRequest {
@SerializedName("PageNumber")
private Long pageNumber;
@SerializedName("PageSize")
private Long pageSize;
@SerializedName("SearchCondition")
private SearchCondition searchCondition;
public Long getPageNumber() { return pageNumber; }
public void setPageNumber(Long pageNumber) { this.pageNumber = pageNumber; }
public Long getPageSize() { return pageSize; }
public void setPageSize(Long pageSize) { this.pageSize = pageSize; }
public SearchCondition getSearchCondition() { return searchCondition; }
public void setSearchCondition(SearchCondition searchCondition) { this.searchCondition = searchCondition; }
}
/**
* SearchCondition
*/
public static class SearchCondition {
@SerializedName("ParentOrgId")
private String parentOrgId;
@SerializedName("OrgIdList")
private List<String> orgIdList;
@SerializedName("DisplayName")
private String displayName;
@SerializedName("OrgId")
private String orgId;
@SerializedName("LastModifiedDate")
private Long lastModifiedDate;
@SerializedName("UpdateDate")
private Long updateDate;
public String getParentOrgId() { return parentOrgId; }
public void setParentOrgId(String parentOrgId) { this.parentOrgId = parentOrgId; }
public List<String> getOrgIdList() { return orgIdList; }
public void setOrgIdList(List<String> orgIdList) { this.orgIdList = orgIdList; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public String getOrgId() { return orgId; }
public void setOrgId(String orgId) { this.orgId = orgId; }
public Long getLastModifiedDate() { return lastModifiedDate; }
public void setLastModifiedDate(Long lastModifiedDate) { this.lastModifiedDate = lastModifiedDate; }
public Long getUpdateDate() { return updateDate; }
public void setUpdateDate(Long updateDate) { this.updateDate = updateDate; }
}
// ==================== 响应类 ====================
/**
* DescribeDepartmentList 响应
*/
public static class DescribeDepartmentListResponse extends BaseResponse<List<Department>> {
public List<Department> getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(List<Department> data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
public Long getTotal() {
return getResponse() != null ? getResponse().getTotal() : null;
}
public void setTotal(Long total) {
if (getResponse() != null) {
getResponse().setTotal(total);
}
}
public Long getPageNumber() {
return getResponse() != null ? getResponse().getPageNumber() : null;
}
public void setPageNumber(Long pageNumber) {
if (getResponse() != null) {
getResponse().setPageNumber(pageNumber);
}
}
public Long getPageSize() {
return getResponse() != null ? getResponse().getPageSize() : null;
}
public void setPageSize(Long pageSize) {
if (getResponse() != null) {
getResponse().setPageSize(pageSize);
}
}
}
/**
* DescribeDepartment 响应
*/
public static class DescribeDepartmentResponse extends BaseResponse<Department> {
public Department getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(Department data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
}
/**
* 部门对象
*/
public static class Department {
@SerializedName("DepartmentId")
private String departmentId;
@SerializedName("CreatedDate")
private Long createdDate;
@SerializedName("LastModifiedDate")
private Long lastModifiedDate;
@SerializedName("UdServiceId")
private String udServiceId;
@SerializedName("DisplayName")
private String displayName;
@SerializedName("Order")
private Integer order;
@SerializedName("Description")
private String description;
@SerializedName("DefaultRootOrg")
private Boolean defaultRootOrg;
@SerializedName("Dn")
private String dn;
@SerializedName("Code")
private String code;
@SerializedName("ParentOrgId")
private String parentOrgId;
@SerializedName("Manager")
private List<String> manager;
@SerializedName("OrgType")
private String orgType;
@SerializedName("Virtual")
private Boolean virtual;
@SerializedName("SearchPath")
private List<String> searchPath;
@SerializedName("DomainID")
private String domainID;
@SerializedName("Deleted")
private Integer deleted;
@SerializedName("AttrValues")
private List<Attribute> attrValues;
@SerializedName("ParentOrgDisplayName")
private String parentOrgDisplayName;
@SerializedName("UserTotal")
private Long userTotal;
// Getters and Setters
public String getDepartmentId() { return departmentId; }
public void setDepartmentId(String departmentId) { this.departmentId = departmentId; }
public Long getCreatedDate() { return createdDate; }
public void setCreatedDate(Long createdDate) { this.createdDate = createdDate; }
public Long getLastModifiedDate() { return lastModifiedDate; }
public void setLastModifiedDate(Long lastModifiedDate) { this.lastModifiedDate = lastModifiedDate; }
public String getUdServiceId() { return udServiceId; }
public void setUdServiceId(String udServiceId) { this.udServiceId = udServiceId; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public Integer getOrder() { return order; }
public void setOrder(Integer order) { this.order = order; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public Boolean getDefaultRootOrg() { return defaultRootOrg; }
public void setDefaultRootOrg(Boolean defaultRootOrg) { this.defaultRootOrg = defaultRootOrg; }
public String getDn() { return dn; }
public void setDn(String dn) { this.dn = dn; }
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
public String getParentOrgId() { return parentOrgId; }
public void setParentOrgId(String parentOrgId) { this.parentOrgId = parentOrgId; }
public List<String> getManager() { return manager; }
public void setManager(List<String> manager) { this.manager = manager; }
public String getOrgType() { return orgType; }
public void setOrgType(String orgType) { this.orgType = orgType; }
public Boolean getVirtual() { return virtual; }
public void setVirtual(Boolean virtual) { this.virtual = virtual; }
public List<String> getSearchPath() { return searchPath; }
public void setSearchPath(List<String> searchPath) { this.searchPath = searchPath; }
public String getDomainID() { return domainID; }
public void setDomainID(String domainID) { this.domainID = domainID; }
public Integer getDeleted() { return deleted; }
public void setDeleted(Integer deleted) { this.deleted = deleted; }
public List<Attribute> getAttrValues() { return attrValues; }
public void setAttrValues(List<Attribute> attrValues) { this.attrValues = attrValues; }
public String getParentOrgDisplayName() { return parentOrgDisplayName; }
public void setParentOrgDisplayName(String parentOrgDisplayName) { this.parentOrgDisplayName = parentOrgDisplayName; }
public Long getUserTotal() { return userTotal; }
public void setUserTotal(Long userTotal) { this.userTotal = userTotal; }
}
/**
* 自定义属性
*/
public static class Attribute {
@SerializedName("AttributeCode")
private String attributeCode;
@SerializedName("AttributeValue")
private Object attributeValue;
public String getAttributeCode() { return attributeCode; }
public void setAttributeCode(String attributeCode) { this.attributeCode = attributeCode; }
public Object getAttributeValue() { return attributeValue; }
public void setAttributeValue(Object attributeValue) { this.attributeValue = attributeValue; }
}
}
package com.keymobile.sso.ud.api;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.keymobile.sso.ud.api.common.BaseResponse;
import com.keymobile.sso.ud.config.ApiConfig;
import com.keymobile.sso.ud.util.HttpClient;
import com.keymobile.sso.ud.util.TencentCloudSignV3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* 用户组API测试类
*/
public class GroupApi {
private static final Logger logger = LoggerFactory.getLogger(GroupApi.class);
private static final Gson gson = new Gson();
private final ApiConfig config;
private final TencentCloudSignV3 signer;
public GroupApi(ApiConfig config) {
this.config = config;
this.signer = new TencentCloudSignV3(config.getSecretId(), config.getSecretKey(), config.getHost());
}
/**
* 获取用户组列表
*/
public DescribeGroupListResponse describeGroupList(Map<String, Object> searchCondition, Long pageNumber, Long pageSize) throws Exception {
String action = "DescribeGroupList";
String url = config.getBaseUrl() + "/auth/api/v1/DescribeGroupList";
Map<String, Object> params = new HashMap<>();
if (searchCondition != null && !searchCondition.isEmpty()) {
params.put("SearchCondition", searchCondition);
}
if (pageNumber != null) {
params.put("PageNumber", pageNumber);
}
if (pageSize != null) {
params.put("PageSize", pageSize);
}
String payload = gson.toJson(params);
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, DescribeGroupListResponse.class);
}
/**
* 获取用户组信息
*/
public DescribeGroupResponse describeGroup(String groupId) throws Exception {
String action = "DescribeGroup";
String url = config.getBaseUrl() + "/auth/api/v1/DescribeGroup";
Map<String, Object> params = new HashMap<>();
params.put("GroupId", groupId);
String payload = gson.toJson(params);
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, DescribeGroupResponse.class);
}
/**
* 获取用户组下的成员列表
*/
public DescribeGroupUserListResponse describeGroupUserList(String groupId, Map<String, Object> searchCondition, List<SortCondition> sort, Long pageNumber, Long pageSize) throws Exception {
String action = "DescribeGroupUserList";
String url = config.getBaseUrl() + "/auth/api/v1/DescribeGroupUserList";
Map<String, Object> params = new HashMap<>();
params.put("GroupId", groupId);
if (searchCondition != null && !searchCondition.isEmpty()) {
params.put("SearchCondition", searchCondition);
}
if (sort != null && !sort.isEmpty()) {
params.put("Sort", sort);
}
if (pageNumber != null) {
params.put("PageNumber", pageNumber);
}
if (pageSize != null) {
params.put("PageSize", pageSize);
}
String payload = gson.toJson(params);
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, DescribeGroupUserListResponse.class);
}
/**
* 构建请求头
*/
private Map<String, String> buildHeaders(String action, String payload, long timestamp) throws Exception {
Map<String, String> headers = signer.buildHeaders(action, payload, timestamp);
headers.put("UdServiceId", config.getUdServiceId());
return headers;
}
// ==================== 响应类 ====================
/**
* DescribeGroupList 响应
*/
public static class DescribeGroupListResponse extends BaseResponse<List<Group>> {
public List<Group> getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(List<Group> data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
public Long getTotal() {
return getResponse() != null ? getResponse().getTotal() : null;
}
public void setTotal(Long total) {
if (getResponse() != null) {
getResponse().setTotal(total);
}
}
public Long getPageNumber() {
return getResponse() != null ? getResponse().getPageNumber() : null;
}
public void setPageNumber(Long pageNumber) {
if (getResponse() != null) {
getResponse().setPageNumber(pageNumber);
}
}
public Long getPageSize() {
return getResponse() != null ? getResponse().getPageSize() : null;
}
public void setPageSize(Long pageSize) {
if (getResponse() != null) {
getResponse().setPageSize(pageSize);
}
}
}
/**
* DescribeGroup 响应
*/
public static class DescribeGroupResponse extends BaseResponse<Group> {
public Group getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(Group data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
}
/**
* DescribeGroupUserList 响应
*/
public static class DescribeGroupUserListResponse extends BaseResponse<List<GroupUser>> {
public List<GroupUser> getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(List<GroupUser> data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
public Long getTotal() {
return getResponse() != null ? getResponse().getTotal() : null;
}
public void setTotal(Long total) {
if (getResponse() != null) {
getResponse().setTotal(total);
}
}
public Long getPageNumber() {
return getResponse() != null ? getResponse().getPageNumber() : null;
}
public void setPageNumber(Long pageNumber) {
if (getResponse() != null) {
getResponse().setPageNumber(pageNumber);
}
}
public Long getPageSize() {
return getResponse() != null ? getResponse().getPageSize() : null;
}
public void setPageSize(Long pageSize) {
if (getResponse() != null) {
getResponse().setPageSize(pageSize);
}
}
}
/**
* 用户组对象
*/
public static class Group {
@SerializedName("GroupId")
private String groupId;
@SerializedName("UdServiceId")
private String udServiceId;
@SerializedName("CreatedDate")
private String createdDate;
@SerializedName("LastModifiedDate")
private String lastModifiedDate;
@SerializedName("DisplayName")
private String displayName;
@SerializedName("OrgId")
private String orgId;
@SerializedName("Code")
private String code;
@SerializedName("Email")
private String email;
@SerializedName("Phone")
private String phone;
@SerializedName("GroupNumber")
private Long groupNumber;
@SerializedName("Description")
private String description;
@SerializedName("Operator")
private String operator;
@SerializedName("Dn")
private String dn;
@SerializedName("DomainID")
private String domainID;
@SerializedName("AttrValues")
private List<Attribute> attrValues;
@SerializedName("OrgPathDisplayName")
private String orgPathDisplayName;
@SerializedName("UserTotal")
private Long userTotal;
// Getters and Setters
public String getGroupId() { return groupId; }
public void setGroupId(String groupId) { this.groupId = groupId; }
public String getUdServiceId() { return udServiceId; }
public void setUdServiceId(String udServiceId) { this.udServiceId = udServiceId; }
public String getCreatedDate() { return createdDate; }
public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
public String getLastModifiedDate() { return lastModifiedDate; }
public void setLastModifiedDate(String lastModifiedDate) { this.lastModifiedDate = lastModifiedDate; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public String getOrgId() { return orgId; }
public void setOrgId(String orgId) { this.orgId = orgId; }
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public Long getGroupNumber() { return groupNumber; }
public void setGroupNumber(Long groupNumber) { this.groupNumber = groupNumber; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getOperator() { return operator; }
public void setOperator(String operator) { this.operator = operator; }
public String getDn() { return dn; }
public void setDn(String dn) { this.dn = dn; }
public String getDomainID() { return domainID; }
public void setDomainID(String domainID) { this.domainID = domainID; }
public List<Attribute> getAttrValues() { return attrValues; }
public void setAttrValues(List<Attribute> attrValues) { this.attrValues = attrValues; }
public String getOrgPathDisplayName() { return orgPathDisplayName; }
public void setOrgPathDisplayName(String orgPathDisplayName) { this.orgPathDisplayName = orgPathDisplayName; }
public Long getUserTotal() { return userTotal; }
public void setUserTotal(Long userTotal) { this.userTotal = userTotal; }
}
/**
* 用户组下的用户对象
*/
public static class GroupUser {
@SerializedName("UserId")
private String userId;
@SerializedName("DisplayName")
private String displayName;
@SerializedName("Username")
private String username;
@SerializedName("UserType")
private String userType;
@SerializedName("Status")
private String status;
@SerializedName("UserStatus")
private String userStatus;
@SerializedName("AccountExpires")
private Long accountExpires;
@SerializedName("Phone")
private String phone;
@SerializedName("SearchPath")
private String searchPath;
@SerializedName("AttrValues")
private List<Attribute> attrValues;
// Getters and Setters
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public String getUserType() { return userType; }
public void setUserType(String userType) { this.userType = userType; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public String getUserStatus() { return userStatus; }
public void setUserStatus(String userStatus) { this.userStatus = userStatus; }
public Long getAccountExpires() { return accountExpires; }
public void setAccountExpires(Long accountExpires) { this.accountExpires = accountExpires; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public String getSearchPath() { return searchPath; }
public void setSearchPath(String searchPath) { this.searchPath = searchPath; }
public List<Attribute> getAttrValues() { return attrValues; }
public void setAttrValues(List<Attribute> attrValues) { this.attrValues = attrValues; }
}
/**
* 自定义属性
*/
public static class Attribute {
@SerializedName("AttributeCode")
private String attributeCode;
@SerializedName("AttributeValue")
private Object attributeValue;
public String getAttributeCode() { return attributeCode; }
public void setAttributeCode(String attributeCode) { this.attributeCode = attributeCode; }
public Object getAttributeValue() { return attributeValue; }
public void setAttributeValue(Object attributeValue) { this.attributeValue = attributeValue; }
}
/**
* 排序条件
*/
public static class SortCondition {
@SerializedName("AttributeCode")
private String attributeCode;
@SerializedName("Type")
private String type;
public String getAttributeCode() { return attributeCode; }
public void setAttributeCode(String attributeCode) { this.attributeCode = attributeCode; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
}
}
\ No newline at end of file
package com.keymobile.sso.ud.api;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.keymobile.sso.ud.api.common.BaseResponse;
import com.keymobile.sso.ud.config.ApiConfig;
import com.keymobile.sso.ud.util.HttpClient;
import com.keymobile.sso.ud.util.TencentCloudSignV3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* 机构管理API测试类
*/
public class OrganizationApi {
private static final Logger logger = LoggerFactory.getLogger(OrganizationApi.class);
private static final Gson gson = new Gson();
private final ApiConfig config;
private final TencentCloudSignV3 signer;
public OrganizationApi(ApiConfig config) {
this.config = config;
this.signer = new TencentCloudSignV3(config.getSecretId(), config.getSecretKey(), config.getHost());
}
/**
* 获取认证域下所有机构列表
*/
public DescribeOrganizationListResponse describeOrganizationList() throws Exception {
String action = "DescribeOrganizationList";
String url = config.getBaseUrl() + "/auth/api/v1/DescribeOrganizationList";
String payload = "{}";
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, DescribeOrganizationListResponse.class);
}
/**
* 机构排序
*/
public SortOrganizationResponse sortOrganization(List<String> orgIdList) throws Exception {
String action = "SortOrganization";
String url = config.getBaseUrl() + "/auth/api/v1/SortOrganization";
Map<String, Object> params = new HashMap<>();
params.put("OrgIdList", orgIdList);
String payload = gson.toJson(params);
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, SortOrganizationResponse.class);
}
/**
* 获取机构信息
*/
public DescribeOrganizationResponse describeOrganization(String orgId) throws Exception {
String action = "DescribeOrganization";
String url = config.getBaseUrl() + "/auth/api/v1/DescribeOrganization";
Map<String, Object> params = new HashMap<>();
params.put("OrgId", orgId);
String payload = gson.toJson(params);
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, DescribeOrganizationResponse.class);
}
/**
* 构建请求头
*/
private Map<String, String> buildHeaders(String action, String payload, long timestamp) throws Exception {
Map<String, String> headers = signer.buildHeaders(action, payload, timestamp);
headers.put("UdServiceId", config.getUdServiceId());
return headers;
}
// ==================== 响应类 ====================
/**
* DescribeOrganizationList 响应
*/
public static class DescribeOrganizationListResponse extends BaseResponse<List<Organization>> {
public List<Organization> getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(List<Organization> data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
}
/**
* SortOrganization 响应
*/
public static class SortOrganizationResponse extends BaseResponse<String> {
public String getOrgId() {
return getData();
}
public void setOrgId(String orgId) {
setData(orgId);
}
public String getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(String data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
}
/**
* DescribeOrganization 响应
*/
public static class DescribeOrganizationResponse extends BaseResponse<Organization> {
public Organization getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(Organization data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
}
/**
* 机构对象
*/
public static class Organization {
@SerializedName("OrgId")
private String orgId;
@SerializedName("CreatedDate")
private String createdDate;
@SerializedName("LastModifiedDate")
private String lastModifiedDate;
@SerializedName("UdServiceId")
private String udServiceId;
@SerializedName("DisplayName")
private String displayName;
@SerializedName("Description")
private String description;
@SerializedName("DefaultRootOrg")
private Boolean defaultRootOrg;
@SerializedName("Dn")
private String dn;
@SerializedName("Code")
private String code;
@SerializedName("Virtual")
private Boolean virtual;
@SerializedName("SearchPath")
private List<String> searchPath;
@SerializedName("DomainID")
private String domainID;
@SerializedName("UserTotal")
private Long userTotal;
// Getters and Setters
public String getOrgId() { return orgId; }
public void setOrgId(String orgId) { this.orgId = orgId; }
public String getCreatedDate() { return createdDate; }
public void setCreatedDate(String createdDate) { this.createdDate = createdDate; }
public String getLastModifiedDate() { return lastModifiedDate; }
public void setLastModifiedDate(String lastModifiedDate) { this.lastModifiedDate = lastModifiedDate; }
public String getUdServiceId() { return udServiceId; }
public void setUdServiceId(String udServiceId) { this.udServiceId = udServiceId; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public Boolean getDefaultRootOrg() { return defaultRootOrg; }
public void setDefaultRootOrg(Boolean defaultRootOrg) { this.defaultRootOrg = defaultRootOrg; }
public String getDn() { return dn; }
public void setDn(String dn) { this.dn = dn; }
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
public Boolean getVirtual() { return virtual; }
public void setVirtual(Boolean virtual) { this.virtual = virtual; }
public List<String> getSearchPath() { return searchPath; }
public void setSearchPath(List<String> searchPath) { this.searchPath = searchPath; }
public String getDomainID() { return domainID; }
public void setDomainID(String domainID) { this.domainID = domainID; }
public Long getUserTotal() { return userTotal; }
public void setUserTotal(Long userTotal) { this.userTotal = userTotal; }
}
}
package com.keymobile.sso.ud.api;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import com.keymobile.sso.ud.api.common.BaseResponse;
import com.keymobile.sso.ud.config.ApiConfig;
import com.keymobile.sso.ud.util.HttpClient;
import com.keymobile.sso.ud.util.TencentCloudSignV3;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
* 用户API测试类
*/
public class UserApi {
private static final Logger logger = LoggerFactory.getLogger(UserApi.class);
private static final Gson gson = new Gson();
private final ApiConfig config;
private final TencentCloudSignV3 signer;
public UserApi(ApiConfig config) {
this.config = config;
this.signer = new TencentCloudSignV3(config.getSecretId(), config.getSecretKey(), config.getHost());
}
/**
* 查询用户
*
* @param userId 用户id(与userName二选一)
* @param userName 用户姓名(与userId二选一)
*/
public DescribeUserResponse describeUser(String userId, String userName) throws Exception {
String action = "DescribeUser";
String url = config.getBaseUrl() + "/auth/api/v1/DescribeUser";
Map<String, Object> params = new HashMap<>();
if (userId != null && !userId.isEmpty()) {
params.put("UserId", userId);
}
if (userName != null && !userName.isEmpty()) {
params.put("UserName", userName);
}
String payload = gson.toJson(params);
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, DescribeUserResponse.class);
}
/**
* 根据用户ID查询用户
*/
public DescribeUserResponse describeUserById(String userId) throws Exception {
return describeUser(userId, null);
}
/**
* 根据用户姓名查询用户
*/
public DescribeUserResponse describeUserByName(String userName) throws Exception {
return describeUser(null, userName);
}
/**
* 查询部门下的用户
*/
public DescribeUsersByOrganizationResponse describeUsersByOrganization(String orgId, Map<String, Object> searchCondition, List<SortCondition> sort, Long pageNumber, Long pageSize) throws Exception {
String action = "DescribeUsersByOrganization";
String url = config.getBaseUrl() + "/auth/api/v1/DescribeUsersByOrganization";
Map<String, Object> params = new HashMap<>();
params.put("OrgId", orgId);
if (searchCondition != null && !searchCondition.isEmpty()) {
params.put("SearchCondition", searchCondition);
}
if (sort != null && !sort.isEmpty()) {
params.put("Sort", sort);
}
if (pageNumber != null) {
params.put("PageNumber", pageNumber);
}
if (pageSize != null) {
params.put("PageSize", pageSize);
}
String payload = gson.toJson(params);
long timestamp = System.currentTimeMillis() / 1000;
Map<String, String> headers = buildHeaders(action, payload, timestamp);
String response = HttpClient.post(url, headers, payload);
return gson.fromJson(response, DescribeUsersByOrganizationResponse.class);
}
/**
* 构建请求头
*/
private Map<String, String> buildHeaders(String action, String payload, long timestamp) throws Exception {
Map<String, String> headers = signer.buildHeaders(action, payload, timestamp);
headers.put("UdServiceId", config.getUdServiceId());
return headers;
}
// ==================== 响应类 ====================
/**
* DescribeUser 响应
*/
public static class DescribeUserResponse extends BaseResponse<User> {
public User getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(User data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
}
/**
* DescribeUsersByOrganization 响应
*/
public static class DescribeUsersByOrganizationResponse extends BaseResponse<List<User>> {
public List<User> getData() {
return getResponse() != null ? getResponse().getData() : null;
}
public void setData(List<User> data) {
if (getResponse() != null) {
getResponse().setData(data);
}
}
public Long getTotal() {
return getResponse() != null ? getResponse().getTotal() : null;
}
public void setTotal(Long total) {
if (getResponse() != null) {
getResponse().setTotal(total);
}
}
public Long getPageNumber() {
return getResponse() != null ? getResponse().getPageNumber() : null;
}
public void setPageNumber(Long pageNumber) {
if (getResponse() != null) {
getResponse().setPageNumber(pageNumber);
}
}
public Long getPageSize() {
return getResponse() != null ? getResponse().getPageSize() : null;
}
public void setPageSize(Long pageSize) {
if (getResponse() != null) {
getResponse().setPageSize(pageSize);
}
}
}
/**
* 排序条件
*/
public static class SortCondition {
@SerializedName("AttributeCode")
private String attributeCode;
@SerializedName("Type")
private String type;
public String getAttributeCode() { return attributeCode; }
public void setAttributeCode(String attributeCode) { this.attributeCode = attributeCode; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
}
/**
* 用户对象
*/
public static class User {
@SerializedName("UdServiceId")
private String udServiceId;
@SerializedName("CreatedDate")
private Long createdDate;
@SerializedName("LastModifiedDate")
private Long lastModifiedDate;
@SerializedName("DisplayName")
private String displayName;
@SerializedName("Name")
private String name;
@SerializedName("Username")
private String username;
@SerializedName("UidNumber")
private Integer uidNumber;
@SerializedName("LastName")
private String lastName;
@SerializedName("AccountExpires")
private Long accountExpires;
@SerializedName("FirstName")
private String firstName;
@SerializedName("Initials")
private String initials;
@SerializedName("Email")
private String email;
@SerializedName("Phone")
private String phone;
@SerializedName("Mobile")
private String mobile;
@SerializedName("Description")
private String description;
@SerializedName("UserType")
private String userType;
@SerializedName("UserStatus")
private String userStatus;
@SerializedName("Status")
private String status;
@SerializedName("Deleted")
private Integer deleted;
@SerializedName("EmployeeId")
private String employeeId;
@SerializedName("Company")
private String company;
@SerializedName("SearchPath")
private String searchPath;
@SerializedName("Department")
private String department;
@SerializedName("PrimaryGroupID")
private Integer primaryGroupID;
@SerializedName("Title")
private String title;
@SerializedName("CountryName")
private String countryName;
@SerializedName("StreetAddress")
private String streetAddress;
@SerializedName("PostalCode")
private String postalCode;
@SerializedName("HomeDirectory")
private String homeDirectory;
@SerializedName("LoginShell")
private String loginShell;
@SerializedName("UserWorkstations")
private String userWorkstations;
@SerializedName("State")
private String state;
@SerializedName("City")
private String city;
@SerializedName("Parent")
private String parent;
@SerializedName("Ou")
private List<String> ou;
@SerializedName("Manager")
private String manager;
@SerializedName("MemberOf")
private List<String> memberOf;
@SerializedName("AttrValues")
private List<Attribute> attrValues;
@SerializedName("UserId")
private String userId;
// Getters and Setters
public String getUdServiceId() { return udServiceId; }
public void setUdServiceId(String udServiceId) { this.udServiceId = udServiceId; }
public Long getCreatedDate() { return createdDate; }
public void setCreatedDate(Long createdDate) { this.createdDate = createdDate; }
public Long getLastModifiedDate() { return lastModifiedDate; }
public void setLastModifiedDate(Long lastModifiedDate) { this.lastModifiedDate = lastModifiedDate; }
public String getDisplayName() { return displayName; }
public void setDisplayName(String displayName) { this.displayName = displayName; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
public Integer getUidNumber() { return uidNumber; }
public void setUidNumber(Integer uidNumber) { this.uidNumber = uidNumber; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public Long getAccountExpires() { return accountExpires; }
public void setAccountExpires(Long accountExpires) { this.accountExpires = accountExpires; }
public String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getInitials() { return initials; }
public void setInitials(String initials) { this.initials = initials; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public String getMobile() { return mobile; }
public void setMobile(String mobile) { this.mobile = mobile; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public String getUserType() { return userType; }
public void setUserType(String userType) { this.userType = userType; }
public String getUserStatus() { return userStatus; }
public void setUserStatus(String userStatus) { this.userStatus = userStatus; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public Integer getDeleted() { return deleted; }
public void setDeleted(Integer deleted) { this.deleted = deleted; }
public String getEmployeeId() { return employeeId; }
public void setEmployeeId(String employeeId) { this.employeeId = employeeId; }
public String getCompany() { return company; }
public void setCompany(String company) { this.company = company; }
public String getSearchPath() { return searchPath; }
public void setSearchPath(String searchPath) { this.searchPath = searchPath; }
public String getDepartment() { return department; }
public void setDepartment(String department) { this.department = department; }
public Integer getPrimaryGroupID() { return primaryGroupID; }
public void setPrimaryGroupID(Integer primaryGroupID) { this.primaryGroupID = primaryGroupID; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getCountryName() { return countryName; }
public void setCountryName(String countryName) { this.countryName = countryName; }
public String getStreetAddress() { return streetAddress; }
public void setStreetAddress(String streetAddress) { this.streetAddress = streetAddress; }
public String getPostalCode() { return postalCode; }
public void setPostalCode(String postalCode) { this.postalCode = postalCode; }
public String getHomeDirectory() { return homeDirectory; }
public void setHomeDirectory(String homeDirectory) { this.homeDirectory = homeDirectory; }
public String getLoginShell() { return loginShell; }
public void setLoginShell(String loginShell) { this.loginShell = loginShell; }
public String getUserWorkstations() { return userWorkstations; }
public void setUserWorkstations(String userWorkstations) { this.userWorkstations = userWorkstations; }
public String getState() { return state; }
public void setState(String state) { this.state = state; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getParent() { return parent; }
public void setParent(String parent) { this.parent = parent; }
public List<String> getOu() { return ou; }
public void setOu(List<String> ou) { this.ou = ou; }
public String getManager() { return manager; }
public void setManager(String manager) { this.manager = manager; }
public List<String> getMemberOf() { return memberOf; }
public void setMemberOf(List<String> memberOf) { this.memberOf = memberOf; }
public List<Attribute> getAttrValues() { return attrValues; }
public void setAttrValues(List<Attribute> attrValues) { this.attrValues = attrValues; }
public String getUserId() { return userId; }
public void setUserId(String userId) { this.userId = userId; }
}
/**
* 职务信息
*/
public static class Duty {
@SerializedName("OrgId")
private String orgId;
@SerializedName("Duty")
private String duty;
@SerializedName("DutyList")
private List<DutyDetail> dutyList;
public String getOrgId() { return orgId; }
public void setOrgId(String orgId) { this.orgId = orgId; }
public String getDuty() { return duty; }
public void setDuty(String duty) { this.duty = duty; }
public List<DutyDetail> getDutyList() { return dutyList; }
public void setDutyList(List<DutyDetail> dutyList) { this.dutyList = dutyList; }
}
/**
* 职务详情
*/
public static class DutyDetail {
@SerializedName("DutyId")
private String dutyId;
@SerializedName("DutyName")
private String dutyName;
public String getDutyId() { return dutyId; }
public void setDutyId(String dutyId) { this.dutyId = dutyId; }
public String getDutyName() { return dutyName; }
public void setDutyName(String dutyName) { this.dutyName = dutyName; }
}
/**
* 自定义属性
*/
public static class Attribute {
@SerializedName("AttributeCode")
private String attributeCode;
@SerializedName("AttributeValue")
private Object attributeValue;
public String getAttributeCode() { return attributeCode; }
public void setAttributeCode(String attributeCode) { this.attributeCode = attributeCode; }
public Object getAttributeValue() { return attributeValue; }
public void setAttributeValue(Object attributeValue) { this.attributeValue = attributeValue; }
}
}
package com.keymobile.sso.ud.api.common;
import com.google.gson.annotations.SerializedName;
/**
* 基础响应类
*/
public class BaseResponse<T> {
@SerializedName("Response")
private Response<T> response;
public Response<T> getResponse() {
return response;
}
public void setResponse(Response<T> response) {
this.response = response;
}
}
\ No newline at end of file
package com.keymobile.sso.ud.api.common;
import com.google.gson.annotations.SerializedName;
/**
* Error
*/
public class Error {
@SerializedName("Code")
private String code;
@SerializedName("Message")
private String message;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
\ No newline at end of file
package com.keymobile.sso.ud.api.common;
import com.google.gson.annotations.SerializedName;
/**
* Response
*/
public class Response<T> {
@SerializedName("RequestId")
private String requestId;
@SerializedName("Error")
private Error error;
@SerializedName("Data")
private T data;
@SerializedName("Total")
private Long total;
@SerializedName("PageNumber")
private Long pageNumber;
@SerializedName("PageSize")
private Long pageSize;
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
public Error getError() {
return error;
}
public void setError(Error error) {
this.error = error;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Long getTotal() {
return total;
}
public void setTotal(Long total) {
this.total = total;
}
public Long getPageNumber() {
return pageNumber;
}
public void setPageNumber(Long pageNumber) {
this.pageNumber = pageNumber;
}
public Long getPageSize() {
return pageSize;
}
public void setPageSize(Long pageSize) {
this.pageSize = pageSize;
}
public boolean isSuccess() {
return error == null;
}
}
\ No newline at end of file
package com.keymobile.sso.ud.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* API配置类
*/
@Component
@EnableConfigurationProperties(ApiConfig.class)
@ConfigurationProperties(prefix = "ud.api")
public class ApiConfig {
private String secretId;
private String secretKey;
private String host;
private String udServiceId;
private String baseUrl;
public ApiConfig() {
}
public ApiConfig(String secretId, String secretKey, String host, String udServiceId) {
this.secretId = secretId;
this.secretKey = secretKey;
this.host = host;
this.udServiceId = udServiceId;
this.baseUrl = "https://" + host;
}
public String getSecretId() {
return secretId;
}
public void setSecretId(String secretId) {
this.secretId = secretId;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public String getHost() {
return host;
}
public void setHost(String host) {
this.host = host;
if (host != null && !host.isEmpty()) {
this.baseUrl = "https://" + host;
}
}
public String getUdServiceId() {
return udServiceId;
}
public void setUdServiceId(String udServiceId) {
this.udServiceId = udServiceId;
}
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
}
package com.keymobile.sso.ud.controller;
import com.keymobile.sso.ud.service.UserGroupResult;
import com.keymobile.sso.ud.service.UserGroupService;
import com.keymobile.sso.ud.service.UserGroupService.SyncResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* 用户组管理接口
*/
@RestController
@RequestMapping("/ud/userGroups")
public class UserGroupController {
private static final Logger logger = LoggerFactory.getLogger(UserGroupController.class);
@Autowired
private UserGroupService userGroupService;
/**
* 获取所有用户组及其成员
* 先分页获取所有用户组,再根据每个GroupId分页获取成员
*
* @return 用户组及其成员列表
*/
@GetMapping("/withMembers")
public UserGroupResult getAllUserGroupsWithMembers() {
logger.info("开始获取所有用户组及其成员");
UserGroupResult result = userGroupService.getAllUserGroupsWithMembers();
logger.info("获取用户组及其成员完成, 总用户组数: {}", result.getTotalGroups());
return result;
}
/**
* 获取所有用户组列表(不包含成员)
*
* @return 用户组列表
*/
@GetMapping("/allUserGroups")
public UserGroupResult getAllUserGroups() {
logger.info("开始获取所有用户组列表");
UserGroupResult result = userGroupService.getAllUserGroups();
logger.info("获取用户组列表完成, 总数: {}", result.getTotalGroups());
return result;
}
/**
* 获取指定用户组的成员
*
* @param groupId 用户组ID
* @return 用户组成员列表
*/
@GetMapping("/{groupId}/members")
public UserGroupResult getGroupMembers(@PathVariable String groupId) {
logger.info("开始获取用户组 {} 的成员", groupId);
UserGroupResult result = userGroupService.getGroupMembers(groupId);
logger.info("获取用户组成员完成");
return result;
}
/**
* 同步用户组和用户数据到AuthService
* 1. 从UD服务获取所有用户组及其成员
* 2. 创建用户组(如果不存在)
* 3. 创建用户(如果不存在)
* 4. 将用户添加到用户组
*
* @return 同步结果
*/
@PostMapping("/sync")
public SyncResult syncUserGroupsAndUsers() {
logger.info("开始同步用户组和用户数据");
SyncResult result = userGroupService.syncUserGroupsAndUsers();
logger.info("同步完成: {}", result.getMessage());
return result;
}
}
package com.keymobile.sso.ud.service;
import com.keymobile.sso.ud.api.GroupApi;
import java.util.List;
/**
* 用户组查询结果类
*/
public class UserGroupResult {
private boolean success;
private String errorMessage;
private Long totalGroups;
private List<UserGroupWithMembers> groups;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public Long getTotalGroups() {
return totalGroups;
}
public void setTotalGroups(Long totalGroups) {
this.totalGroups = totalGroups;
}
public List<UserGroupWithMembers> getGroups() {
return groups;
}
public void setGroups(List<UserGroupWithMembers> groups) {
this.groups = groups;
}
/**
* 用户组及其成员详情
*/
public static class UserGroupWithMembers {
private String groupId;
private String displayName;
private String description;
private String orgId;
private Long userTotal;
private List<GroupApi.GroupUser> members;
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getOrgId() {
return orgId;
}
public void setOrgId(String orgId) {
this.orgId = orgId;
}
public Long getUserTotal() {
return userTotal;
}
public void setUserTotal(Long userTotal) {
this.userTotal = userTotal;
}
public List<GroupApi.GroupUser> getMembers() {
return members;
}
public void setMembers(List<GroupApi.GroupUser> members) {
this.members = members;
}
}
}
package com.keymobile.sso.ud.service;
import com.keymobile.sso.service.AuthService;
import com.keymobile.sso.ud.api.GroupApi;
import com.keymobile.sso.ud.config.ApiConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import static com.keymobile.sso.api.Constants.*;
/**
* 用户组服务类
* 用于分页获取所有用户组及其成员
*/
@Service
public class UserGroupService {
private static final Logger logger = LoggerFactory.getLogger(UserGroupService.class);
private static final long DEFAULT_PAGE_SIZE = 100;
private final GroupApi groupApi;
private final AuthService authService;
public UserGroupService(ApiConfig apiConfig, AuthService authService) {
this.groupApi = new GroupApi(apiConfig);
this.authService = authService;
}
/**
* 获取所有用户组及其成员
*
* @return 包含所有用户组及其成员的结果
*/
public UserGroupResult getAllUserGroupsWithMembers() {
UserGroupResult result = new UserGroupResult();
List<UserGroupResult.UserGroupWithMembers> allGroups = new ArrayList<>();
try {
long currentPage = 1;
long pageSize = DEFAULT_PAGE_SIZE;
long totalGroups = 0;
do {
GroupApi.DescribeGroupListResponse groupListResponse = groupApi.describeGroupList(null, currentPage, pageSize);
if (!groupListResponse.getResponse().isSuccess()) {
logger.error("获取用户组列表失败: {} - {}",
groupListResponse.getResponse().getError().getCode(),
groupListResponse.getResponse().getError().getMessage());
result.setSuccess(false);
result.setErrorMessage("获取用户组列表失败: " + groupListResponse.getResponse().getError().getMessage());
return result;
}
List<GroupApi.Group> groups = groupListResponse.getData();
if (groups == null || groups.isEmpty()) {
break;
}
totalGroups = groupListResponse.getTotal() != null ? groupListResponse.getTotal() : 0;
for (GroupApi.Group group : groups) {
UserGroupResult.UserGroupWithMembers groupWithMembers = new UserGroupResult.UserGroupWithMembers();
groupWithMembers.setGroupId(group.getGroupId());
groupWithMembers.setDisplayName(group.getDisplayName());
groupWithMembers.setDescription(group.getDescription());
groupWithMembers.setOrgId(group.getOrgId());
groupWithMembers.setUserTotal(group.getUserTotal());
List<GroupApi.GroupUser> members = getAllMembersByGroupId(group.getGroupId());
groupWithMembers.setMembers(members);
allGroups.add(groupWithMembers);
logger.info("已处理用户组: {} - {}, 成员数: {}", group.getGroupId(), group.getDisplayName(), members.size());
}
currentPage++;
} while ((currentPage - 1) * pageSize < totalGroups);
result.setSuccess(true);
result.setGroups(allGroups);
result.setTotalGroups(totalGroups);
} catch (Exception e) {
logger.error("获取用户组及其成员失败", e);
result.setSuccess(false);
result.setErrorMessage("获取用户组及其成员失败: " + e.getMessage());
}
return result;
}
/**
* 根据用户组ID获取该组下所有成员
*
* @param groupId 用户组ID
* @return 用户组成员列表
*/
private List<GroupApi.GroupUser> getAllMembersByGroupId(String groupId) {
List<GroupApi.GroupUser> allMembers = new ArrayList<>();
try {
long currentPage = 1;
long pageSize = DEFAULT_PAGE_SIZE;
long totalMembers = 0;
do {
GroupApi.DescribeGroupUserListResponse userListResponse = groupApi.describeGroupUserList(
groupId, null, null, currentPage, pageSize);
if (!userListResponse.getResponse().isSuccess()) {
logger.error("获取用户组成员列表失败: {} - {}",
userListResponse.getResponse().getError().getCode(),
userListResponse.getResponse().getError().getMessage());
break;
}
List<GroupApi.GroupUser> members = userListResponse.getData();
if (members == null || members.isEmpty()) {
break;
}
totalMembers = userListResponse.getTotal() != null ? userListResponse.getTotal() : 0;
allMembers.addAll(members);
currentPage++;
} while ((currentPage - 1) * pageSize < totalMembers);
} catch (Exception e) {
logger.error("获取用户组 {} 的成员失败", groupId, e);
}
return allMembers;
}
/**
* 获取所有用户组列表(不分页获取成员)
*
* @return 用户组列表结果
*/
public UserGroupResult getAllUserGroups() {
UserGroupResult result = new UserGroupResult();
List<UserGroupResult.UserGroupWithMembers> allGroups = new ArrayList<>();
try {
long currentPage = 1;
long pageSize = DEFAULT_PAGE_SIZE;
long totalGroups = 0;
do {
GroupApi.DescribeGroupListResponse groupListResponse = groupApi.describeGroupList(null, currentPage, pageSize);
if (!groupListResponse.getResponse().isSuccess()) {
logger.error("获取用户组列表失败: {} - {}",
groupListResponse.getResponse().getError().getCode(),
groupListResponse.getResponse().getError().getMessage());
result.setSuccess(false);
result.setErrorMessage("获取用户组列表失败: " + groupListResponse.getResponse().getError().getMessage());
return result;
}
List<GroupApi.Group> groups = groupListResponse.getData();
if (groups == null || groups.isEmpty()) {
break;
}
totalGroups = groupListResponse.getTotal() != null ? groupListResponse.getTotal() : 0;
for (GroupApi.Group group : groups) {
UserGroupResult.UserGroupWithMembers groupWithMembers = new UserGroupResult.UserGroupWithMembers();
groupWithMembers.setGroupId(group.getGroupId());
groupWithMembers.setDisplayName(group.getDisplayName());
groupWithMembers.setDescription(group.getDescription());
groupWithMembers.setOrgId(group.getOrgId());
groupWithMembers.setUserTotal(group.getUserTotal());
allGroups.add(groupWithMembers);
}
currentPage++;
} while ((currentPage - 1) * pageSize < totalGroups);
result.setSuccess(true);
result.setGroups(allGroups);
result.setTotalGroups(totalGroups);
} catch (Exception e) {
logger.error("获取用户组列表失败", e);
result.setSuccess(false);
result.setErrorMessage("获取用户组列表失败: " + e.getMessage());
}
return result;
}
/**
* 获取指定用户组的成员
*
* @param groupId 用户组ID
* @return 用户组成员结果
*/
public UserGroupResult getGroupMembers(String groupId) {
UserGroupResult result = new UserGroupResult();
List<UserGroupResult.UserGroupWithMembers> groups = new ArrayList<>();
try {
GroupApi.DescribeGroupResponse groupResponse = groupApi.describeGroup(groupId);
if (!groupResponse.getResponse().isSuccess()) {
result.setSuccess(false);
result.setErrorMessage("获取用户组信息失败: " + groupResponse.getResponse().getError().getMessage());
return result;
}
GroupApi.Group group = groupResponse.getData();
if (group == null) {
result.setSuccess(false);
result.setErrorMessage("用户组不存在");
return result;
}
List<GroupApi.GroupUser> members = getAllMembersByGroupId(groupId);
UserGroupResult.UserGroupWithMembers groupWithMembers = new UserGroupResult.UserGroupWithMembers();
groupWithMembers.setGroupId(group.getGroupId());
groupWithMembers.setDisplayName(group.getDisplayName());
groupWithMembers.setDescription(group.getDescription());
groupWithMembers.setOrgId(group.getOrgId());
groupWithMembers.setUserTotal(group.getUserTotal());
groupWithMembers.setMembers(members);
groups.add(groupWithMembers);
result.setSuccess(true);
result.setGroups(groups);
result.setTotalGroups(1L);
} catch (Exception e) {
logger.error("获取用户组 {} 的成员失败", groupId, e);
result.setSuccess(false);
result.setErrorMessage("获取用户组成员失败: " + e.getMessage());
}
return result;
}
/**
* 同步用户组和用户数据到AuthService
* 1. 获取所有用户组及其成员
* 2. 创建用户组(如不存在)
* 3. 创建用户(如不存在)
* 4. 将用户添加到用户组
*
* @return 同步结果
*/
public SyncResult syncUserGroupsAndUsers() {
SyncResult result = new SyncResult();
try {
logger.info("开始同步用户组和用户数据...");
UserGroupResult userGroupResult = getAllUserGroupsWithMembers();
if (!userGroupResult.isSuccess()) {
result.setSuccess(false);
result.setErrorMessage("获取用户组数据失败: " + userGroupResult.getErrorMessage());
return result;
}
List<UserGroupResult.UserGroupWithMembers> groups = userGroupResult.getGroups();
if (groups == null || groups.isEmpty()) {
result.setSuccess(true);
result.setMessage("没有需要同步的用户组数据");
return result;
}
List<Map<String, Object>> existingUsers = authService.getAllUsers(new String[0]);
Map<String, Long> userIdMap = buildUserIdMap(existingUsers);
List<Map<String, Object>> existingGroups = authService.findAllUserGroups();
Map<String, Long> groupNameIdMap = buildGroupNameIdMap(existingGroups);
int createdGroupCount = 0;
int createdUserCount = 0;
int addedMemberCount = 0;
int skippedGroupCount = 0;
for (UserGroupResult.UserGroupWithMembers groupWithMembers : groups) {
String groupName = groupWithMembers.getDisplayName();
if (groupName == null || groupName.isEmpty()) {
groupName = groupWithMembers.getGroupId();
}
Long groupId = groupNameIdMap.get(groupName);
if (groupId == null) {
Map<String, Object> newGroup = new HashMap<>();
newGroup.put("name", groupName);
newGroup.put("desc", groupWithMembers.getDescription());
Map<String, Object> addResult = authService.addUserGroup(newGroup);
if (addResult != null && addResult.get("id") != null) {
groupId = ((Number) addResult.get("id")).longValue();
groupNameIdMap.put(groupName, groupId);
createdGroupCount++;
logger.info("创建用户组成功: {} - ID: {}", groupName, groupId);
} else {
logger.warn("创建用户组失败: {}", groupName);
skippedGroupCount++;
continue;
}
}
List<GroupApi.GroupUser> members = groupWithMembers.getMembers();
if (members == null || members.isEmpty()) {
continue;
}
List<Long> memberUserIds = new ArrayList<>();
for (GroupApi.GroupUser member : members) {
String username = member.getDisplayName();
if (username == null || username.isEmpty()) {
username = member.getUserId();
}
Long userId = userIdMap.get(username);
if (userId == null) {
Map<String, Object> newUser = new HashMap<>();
newUser.put(USER_INFO_D_NAME, username);
newUser.put(USER_INFO_NAME, member.getDisplayName() != null ? member.getDisplayName() : username);
newUser.put(USER_INFO_PASSWORD, "37fa265330ad83eaa879efb1e2db6380896cf639");
Map<String, Object> addUserResult = authService.addUser(newUser);
if (addUserResult != null && addUserResult.get("id") != null) {
userId = ((Number) addUserResult.get("id")).longValue();
userIdMap.put(username, userId);
createdUserCount++;
logger.info("创建用户成功: {} - ID: {}", username, userId);
} else {
logger.warn("创建用户失败: {}", username);
continue;
}
}
memberUserIds.add(userId);
}
if (!memberUserIds.isEmpty()) {
try {
Long[] userIdsArray = memberUserIds.toArray(new Long[0]);
authService.addUser(groupId, userIdsArray);
addedMemberCount += memberUserIds.size();
logger.info("添加用户到用户组成功: {}, 用户数: {}", groupName, memberUserIds.size());
} catch (Exception e) {
logger.warn("添加用户到用户组失败: {}", groupName, e);
}
}
}
result.setSuccess(true);
result.setCreatedGroupCount(createdGroupCount);
result.setCreatedUserCount(createdUserCount);
result.setAddedMemberCount(addedMemberCount);
result.setSkippedGroupCount(skippedGroupCount);
result.setMessage(String.format("同步完成: 创建用户组 %d 个, 创建用户 %d 个, 添加成员 %d 个",
createdGroupCount, createdUserCount, addedMemberCount));
logger.info("同步完成: {}", result.getMessage());
} catch (Exception e) {
logger.error("同步用户组和用户数据失败", e);
result.setSuccess(false);
result.setErrorMessage("同步失败: " + e.getMessage());
}
return result;
}
/**
* 构建用户ID映射表 (username -> id)
*/
private Map<String, Long> buildUserIdMap(List<Map<String, Object>> users) {
Map<String, Long> userMap = new ConcurrentHashMap<>();
if (users != null) {
for (Map<String, Object> user : users) {
Object username = user.get("username");
Object id = user.get("id");
if (username != null && id != null) {
userMap.put(username.toString(), ((Number) id).longValue());
}
}
}
return userMap;
}
/**
* 构建用户组ID映射表 (name -> id)
*/
private Map<String, Long> buildGroupNameIdMap(List<Map<String, Object>> groups) {
Map<String, Long> groupMap = new ConcurrentHashMap<>();
if (groups != null) {
for (Map<String, Object> group : groups) {
Object name = group.get("name");
Object id = group.get("id");
if (name != null && id != null) {
groupMap.put(name.toString(), ((Number) id).longValue());
}
}
}
return groupMap;
}
/**
* 同步结果类
*/
public static class SyncResult {
private boolean success;
private String message;
private String errorMessage;
private int createdGroupCount;
private int createdUserCount;
private int addedMemberCount;
private int skippedGroupCount;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getErrorMessage() {
return errorMessage;
}
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
public int getCreatedGroupCount() {
return createdGroupCount;
}
public void setCreatedGroupCount(int createdGroupCount) {
this.createdGroupCount = createdGroupCount;
}
public int getCreatedUserCount() {
return createdUserCount;
}
public void setCreatedUserCount(int createdUserCount) {
this.createdUserCount = createdUserCount;
}
public int getAddedMemberCount() {
return addedMemberCount;
}
public void setAddedMemberCount(int addedMemberCount) {
this.addedMemberCount = addedMemberCount;
}
public int getSkippedGroupCount() {
return skippedGroupCount;
}
public void setSkippedGroupCount(int skippedGroupCount) {
this.skippedGroupCount = skippedGroupCount;
}
}
}
package com.keymobile.sso.ud.util;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.Map;
/**
* HTTP客户端工具类
*/
public class HttpClient {
private static final Logger logger = LoggerFactory.getLogger(HttpClient.class);
private static final Gson gson = new GsonBuilder().setPrettyPrinting().create();
/**
* 发送POST请求
*
* @param url 请求URL
* @param headers 请求头
* @param payload 请求体JSON
* @return 响应JSON字符串
*/
public static String post(String url, Map<String, String> headers, String payload) throws Exception {
logger.info("Request URL: {}", url);
logger.info("Request Headers: {}", headers);
logger.info("Request Payload: {}", payload);
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(url);
if (headers != null) {
for (Map.Entry<String, String> entry : headers.entrySet()) {
httpPost.setHeader(entry.getKey(), entry.getValue());
}
}
if (payload != null && !payload.isEmpty()) {
httpPost.setEntity(new StringEntity(payload, StandardCharsets.UTF_8));
}
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
HttpEntity entity = response.getEntity();
String result = entity != null ? EntityUtils.toString(entity, StandardCharsets.UTF_8) : "";
logger.info("\nResponse: {}", result);
return result;
}
}
}
/**
* 发送POST请求并解析响应
*
* @param url 请求URL
* @param headers 请求头
* @param payload 请求体对象
* @param clazz 响应类型
* @param <T> 响应类型泛型
* @return 响应对象
*/
public static <T> T post(String url, Map<String, String> headers, Object payload, Class<T> clazz) throws Exception {
String payloadJson = payload != null ? gson.toJson(payload) : "";
String response = post(url, headers, payloadJson);
return gson.fromJson(response, clazz);
}
/**
* 格式化JSON字符串
*/
public static String formatJson(String json) {
try {
Object obj = gson.fromJson(json, Object.class);
return gson.toJson(obj);
} catch (Exception e) {
return json;
}
}
}
package com.keymobile.sso.ud.util;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
/**
* 腾讯云V3签名工具类
* 参考文档: https://cloud.tencent.com/document/product/628/45174
*/
public class TencentCloudSignV3 {
private static final String ALGORITHM = "TC3-HMAC-SHA256";
private static final String SERVICE = "ud";
private static final String CT_JSON = "application/json; charset=utf-8";
private static final String TC3_REQUEST = "tc3_request";
private final String secretId;
private final String secretKey;
private final String host;
public TencentCloudSignV3(String secretId, String secretKey, String host) {
this.secretId = secretId;
this.secretKey = secretKey;
this.host = host;
}
/**
* 生成签名
*
* @param action 接口地址
* @param payload 请求体JSON字符串
* @param timestamp 时间戳
* @return 签名Authorization
*/
public String sign(String action, String payload, long timestamp) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
sdf.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
String date = sdf.format(new Date(timestamp * 1000));
String hashedPayload = sha256Hex(payload);
String canonicalRequest = buildCanonicalRequest(action, hashedPayload);
String credentialScope = date + "/" + SERVICE + "/" + TC3_REQUEST;
String hashedCanonicalRequest = sha256Hex(canonicalRequest);
String stringToSign = buildStringToSign(String.valueOf(timestamp), credentialScope, hashedCanonicalRequest);
String signature = calculateSignature(date, stringToSign);
return buildAuthorization(credentialScope, signature);
}
/**
* 构建规范请求串
*/
private String buildCanonicalRequest(String action, String hashedPayload) {
String httpRequestMethod = "POST";
String canonicalUri = "/";
String canonicalQueryString = "";
String canonicalHeaders = "content-type:" + CT_JSON + "\n" +
"host:" + host + "\n" +
"x-tc-action:" + action.toLowerCase() + "\n";
String signedHeaders = "content-type;host;x-tc-action";
return httpRequestMethod + "\n" +
canonicalUri + "\n" +
canonicalQueryString + "\n" +
canonicalHeaders + "\n" +
signedHeaders + "\n" +
hashedPayload;
}
/**
* 拼接待签名字符串
*/
private String buildStringToSign(String timestamp, String credentialScope, String hashedCanonicalRequest) {
return ALGORITHM + "\n" +
timestamp + "\n" +
credentialScope + "\n" +
hashedCanonicalRequest;
}
/**
* 计算签名
*/
private String calculateSignature(String date, String stringToSign) throws Exception {
byte[] secretDate = hmac256(("TC3" + secretKey).getBytes(StandardCharsets.UTF_8), date);
byte[] secretService = hmac256(secretDate, SERVICE);
byte[] secretSigning = hmac256(secretService, TC3_REQUEST);
return bytesToHex(hmac256(secretSigning, stringToSign));
}
/**
* 构建Authorization头
*/
private String buildAuthorization(String credentialScope, String signature) {
String signedHeaders = "content-type;host;x-tc-action";
return ALGORITHM + " " +
"Credential=" + secretId + "/" + credentialScope + ", " +
"SignedHeaders=" + signedHeaders + ", " +
"Signature=" + signature;
}
/**
* 构建HTTP请求头Map
*/
public Map<String, String> buildHeaders(String action, String payload, long timestamp) throws Exception {
Map<String, String> headers = new TreeMap<>();
headers.put("Authorization", sign(action, payload, timestamp));
headers.put("Content-Type", CT_JSON);
headers.put("Host", host);
headers.put("X-TC-Action", action);
headers.put("X-TC-Timestamp", String.valueOf(timestamp));
headers.put("X-TC-Version", "2017-03-12");
return headers;
}
/**
* HMAC-SHA256计算
*/
private byte[] hmac256(byte[] key, String msg) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, mac.getAlgorithm());
mac.init(secretKeySpec);
return mac.doFinal(msg.getBytes(StandardCharsets.UTF_8));
}
/**
* SHA256哈希
*/
private String sha256Hex(String s) throws Exception {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] d = md.digest(s.getBytes(StandardCharsets.UTF_8));
return bytesToHex(d);
}
/**
* byte数组转十六进制字符串
*/
private String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
}
return sb.toString();
}
}
...@@ -12,6 +12,12 @@ spring: ...@@ -12,6 +12,12 @@ spring:
read-timeout: 5000 read-timeout: 5000
profiles: profiles:
active: default active: default
ud:
api:
secret-id: 964a5eb6c336475caf9a9830d0ee357d
secret-key: fb7f49a789bd473681bdafef5770907a
host: portal-udadmin.sznsmic.com
ud-service-id: dfaaad6a-87f2-419b-98d0-9a950be8e479
management: management:
metrics: metrics:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment