KeycloakServiceImpl.java 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. package com.inspur.customer.service.keycloak;
  2. import com.alibaba.cola.dto.PageResponse;
  3. import com.alibaba.cola.dto.Response;
  4. import com.alibaba.cola.dto.SingleResponse;
  5. import com.google.common.collect.Lists;
  6. import com.inspur.customer.client.keycloak.KeycloakService;
  7. import com.inspur.customer.constant.Constant;
  8. import com.inspur.customer.object.keycloak.KeycloakUserCO;
  9. import com.inspur.customer.object.keycloak.SwitchDTO;
  10. import com.inspur.customer.object.keycloak.UsersRoleMappingDTO;
  11. import com.inspur.customer.object.org.SmsbDepartmentCmd;
  12. import com.inspur.customer.object.org.SmsbUserAdd;
  13. import com.inspur.customer.object.wechat.Pair;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.apache.dubbo.config.annotation.DubboService;
  16. import org.keycloak.admin.client.resource.*;
  17. import org.keycloak.representations.idm.*;
  18. import org.springframework.cache.annotation.CacheEvict;
  19. import org.springframework.cache.annotation.Cacheable;
  20. import org.springframework.scheduling.annotation.Scheduled;
  21. import org.springframework.util.CollectionUtils;
  22. import org.springframework.util.StringUtils;
  23. import javax.annotation.Resource;
  24. import java.time.LocalDateTime;
  25. import java.util.*;
  26. import java.util.concurrent.atomic.AtomicReference;
  27. import java.util.stream.Collectors;
  28. import java.util.stream.Stream;
  29. @Slf4j
  30. @DubboService
  31. public class KeycloakServiceImpl implements KeycloakService {
  32. @Resource
  33. private RealmResource realmResource;
  34. @Override
  35. @Cacheable(value = "smsb:users")
  36. public Map<String, String> getUserMap() {
  37. Map<String, String> userMap = new HashMap<>();
  38. realmResource.users().list().forEach(user ->{
  39. if (user.getFirstName() != null && user.getLastName() != null && !"".equals(user.getLastName())) {
  40. user.setUsername(user.getLastName() + user.getFirstName());
  41. }
  42. userMap.put(user.getId(),user.getUsername());
  43. });
  44. return userMap;
  45. }
  46. @CacheEvict(value = "smsb:users" , allEntries = true)
  47. public void clearUserMapCache(){
  48. log.info("users map cache clear:{}",LocalDateTime.now() );
  49. }
  50. @Scheduled(cron = "* 0/10 * * * ?")
  51. public void expiredCache(){
  52. // 每隔10小时,清除缓存数据初始化一次
  53. this.clearUserMapCache();
  54. }
  55. /**
  56. * get users in role (xuzhou environment)
  57. * @param role role
  58. * @return users
  59. */
  60. @Override
  61. public List<KeycloakUserCO> getUsersInRole(String role) {
  62. List<KeycloakUserCO> keycloakUserCos = new ArrayList<>();
  63. realmResource.roles().get(role).getRoleUserMembers().forEach(user -> {
  64. log.info("name: {}", user.getUsername());
  65. KeycloakUserCO keycloakUserCo = new KeycloakUserCO();
  66. keycloakUserCo.setId(user.getId());
  67. keycloakUserCo.setEmail(user.getEmail());
  68. Map<String, List<String>> attributes = user.getAttributes();
  69. if (attributes != null) {
  70. keycloakUserCo.setPhone(attributes.get("phone"));
  71. keycloakUserCo.setWechat(attributes.get("wechat"));
  72. keycloakUserCo.setWechatApplet(attributes.get("wechat-applet-openid"));
  73. }
  74. keycloakUserCos.add(keycloakUserCo);
  75. });
  76. return keycloakUserCos;
  77. }
  78. /**
  79. * get users by ids
  80. * according to device's related users is no too much, temporary use that way to get users
  81. * @deprecated
  82. * @param userIds ids
  83. * @return users
  84. */
  85. @Override
  86. public List<KeycloakUserCO> getUsersByIds(List<String> userIds) {
  87. List<KeycloakUserCO> keycloakUserCos = new ArrayList<>(userIds.size());
  88. userIds.forEach(id -> {
  89. UserRepresentation userRepresentation = realmResource.users().get(id).toRepresentation();
  90. if (userRepresentation != null) {
  91. KeycloakUserCO keycloakUserCo = new KeycloakUserCO();
  92. keycloakUserCo.setId(userRepresentation.getId());
  93. keycloakUserCo.setUsername(userRepresentation.getUsername());
  94. keycloakUserCo.setEmail(userRepresentation.getEmail());
  95. Map<String, List<String>> attributes = userRepresentation.getAttributes();
  96. if (attributes != null) {
  97. keycloakUserCo.setPhone(attributes.get("phone"));
  98. keycloakUserCo.setWechat(attributes.get("wechat"));
  99. keycloakUserCo.setWechatApplet(attributes.get("wechat-applet-openid"));
  100. }
  101. keycloakUserCos.add(keycloakUserCo);
  102. }
  103. });
  104. return keycloakUserCos;
  105. }
  106. @Override
  107. public Boolean checkUserRole(String userId, String role) {
  108. AtomicReference<Boolean> result = new AtomicReference<>(false);
  109. List<RoleRepresentation> roles = realmResource.users().get(userId).roles().getAll().getRealmMappings();
  110. log.info("userId:{},roles:{}",userId , roles);
  111. roles.forEach(n ->{
  112. if(n.getName().equalsIgnoreCase(role)){
  113. result.set(true);
  114. }
  115. });
  116. return result.get();
  117. }
  118. @Override
  119. public void updateAttribute(String userId ,String property , String value) {
  120. UserResource user = realmResource.users().get(userId);
  121. UserRepresentation userRepresentation = user.toRepresentation();
  122. if (userRepresentation.getAttributes() == null) {
  123. userRepresentation.setAttributes(new HashMap<>());
  124. }
  125. userRepresentation.getAttributes().put(property, Collections.singletonList(value));
  126. user.update(userRepresentation);
  127. }
  128. @Override
  129. public List<String> getAttrByGroupPath(String groupPath, String key) {
  130. GroupRepresentation groupRepresentation = realmResource.getGroupByPath(groupPath);
  131. if (groupRepresentation != null) {
  132. Map<String, List<String>> attributes = groupRepresentation.getAttributes();
  133. return attributes != null ? attributes.get(key) : Collections.emptyList();
  134. }
  135. return Collections.emptyList();
  136. }
  137. @Override
  138. public List<KeycloakUserCO> getGroupSupervisor(String group) {
  139. return getUserByRoleAndGroup(group, "ROLE_OPERATION_SUPERVISOR");
  140. }
  141. @Override
  142. public List<KeycloakUserCO> getSuperAdmin() {
  143. return realmResource.roles().get("ROLE_SUPER_ADMIN").getRoleUserMembers()
  144. .stream()
  145. .map(this::transfer)
  146. .collect(Collectors.toList());
  147. }
  148. @Override
  149. public List<KeycloakUserCO> getAllRoleAdmin() {
  150. return realmResource.roles().get("ROLE_ADMIN").getRoleUserMembers()
  151. .stream()
  152. .map(this::transfer)
  153. .collect(Collectors.toList());
  154. }
  155. @Override
  156. public List<KeycloakUserCO> getAllRoleOperationSupervisor() {
  157. return realmResource.roles().get("ROLE_OPERATION_SUPERVISOR").getRoleUserMembers()
  158. .stream()
  159. .map(this::transfer)
  160. .collect(Collectors.toList());
  161. }
  162. @Override
  163. public List<KeycloakUserCO> getGroupAdmin(String group) {
  164. return getUserByRoleAndGroup(group, "ROLE_ADMIN");
  165. }
  166. @Override
  167. public String getSingleAttrByGroupPath(String group, String key) {
  168. List<String> list = getAttrByGroupPath(group, key);
  169. if (CollectionUtils.isEmpty(list)) {
  170. return null;
  171. } else {
  172. return list.get(0);
  173. }
  174. }
  175. @Override
  176. public List<KeycloakUserCO> searchUserByAttrEntry(List<Pair> pairList) {
  177. String search = pairList.stream()
  178. .filter(t -> Objects.nonNull(t) && Objects.nonNull(t.getKey()) && Objects.nonNull(t.getValue()))
  179. .map(t -> t.getKey() + ":" + t.getValue())
  180. .collect(Collectors.joining(" "));
  181. return realmResource.users().searchByAttributes(search).stream().map(this::transfer).collect(Collectors.toList());
  182. }
  183. @Override
  184. public List<String> getUserGroupPathList(String userId) {
  185. return realmResource.users().get(userId).groups().stream().map(GroupRepresentation::getPath).collect(Collectors.toList());
  186. }
  187. @Override
  188. public List<String> getUserRealmRoles(String userId) {
  189. return realmResource
  190. .users()
  191. .get(userId)
  192. .roles()
  193. .getAll()
  194. .getRealmMappings()
  195. .stream()
  196. .map(RoleRepresentation::getName)
  197. .collect(Collectors.toList());
  198. }
  199. @Override
  200. public Map<String, List<String>> getUserClientRoles(String userId) {
  201. Map<String, List<String>> resultMap = new HashMap<>();
  202. List<ClientRepresentation> clientList = realmResource.clients().findAll();
  203. for (ClientRepresentation clientRepresentation : clientList) {
  204. String clientId = clientRepresentation.getClientId();
  205. List<RoleRepresentation> roleList = realmResource.users().get(userId).roles().clientLevel(clientRepresentation.getId()).listEffective();
  206. if (!roleList.isEmpty()) {
  207. resultMap.put(clientId, roleList.stream().map(RoleRepresentation::getName).collect(Collectors.toList()));
  208. }
  209. }
  210. return resultMap;
  211. }
  212. @Override
  213. public void changePassword(String userId, String newPassword) {
  214. CredentialRepresentation cr = new CredentialRepresentation();
  215. cr.setType(CredentialRepresentation.PASSWORD);
  216. cr.setValue(newPassword);
  217. realmResource.users().get(userId).resetPassword(cr);
  218. }
  219. private List<KeycloakUserCO> getUserByRoleAndGroup(String group, String role) {
  220. if (!StringUtils.hasText(group) || !StringUtils.hasText(role)) {
  221. return Collections.emptyList();
  222. }
  223. List<UserRepresentation> members = realmResource.groups().group(realmResource.getGroupByPath(group).getId()).members();
  224. Set<String> set = realmResource.roles().get(role).getRoleUserMembers().stream().map(UserRepresentation::getId).collect(Collectors.toSet());
  225. return members.stream().filter(t -> set.contains(t.getId())).map(this::transfer).collect(Collectors.toList());
  226. }
  227. private KeycloakUserCO transfer(UserRepresentation userRepresentation) {
  228. if (userRepresentation == null) {
  229. return null;
  230. }
  231. KeycloakUserCO keycloakUserCo = new KeycloakUserCO();
  232. keycloakUserCo.setId(userRepresentation.getId());
  233. keycloakUserCo.setUsername(userRepresentation.getUsername());
  234. keycloakUserCo.setEmail(userRepresentation.getEmail());
  235. Map<String, List<String>> attributes = userRepresentation.getAttributes();
  236. if (attributes != null) {
  237. keycloakUserCo.setPhone(attributes.get("phone"));
  238. keycloakUserCo.setWechat(attributes.get("wechat"));
  239. keycloakUserCo.setWechatApplet(attributes.get("wechat-applet-openid"));
  240. }
  241. return keycloakUserCo;
  242. }
  243. @Override
  244. @Cacheable(value = "smsb:userList")
  245. public Map<String, String> getUsersMap() {
  246. Map<String, String> userMap = new HashMap<>();
  247. realmResource.users().list().forEach(user ->{
  248. if (user.getFirstName() != null && user.getLastName() != null && !"".equals(user.getLastName())) {
  249. user.setUsername(user.getLastName() + user.getFirstName());
  250. }
  251. userMap.put(user.getId(),user.getUsername());
  252. });
  253. return userMap;
  254. }
  255. @Override
  256. public Response addKeycloakGroup(String id , GroupRepresentation groupRepresentation) {
  257. return SingleResponse.of(realmResource.groups().group(id).subGroup(groupRepresentation).getDate());
  258. }
  259. @Override
  260. public Response updateKeycloakGroup(String id, GroupRepresentation groupRepresentation) {
  261. realmResource.groups().group(id).update(groupRepresentation);
  262. return SingleResponse.buildSuccess();
  263. }
  264. @Override
  265. public Response removeGroup(String id) {
  266. realmResource.groups().group(id).remove();
  267. return SingleResponse.buildSuccess();
  268. }
  269. @Override
  270. public SingleResponse addKeyClaokUser(SmsbUserAdd user) {
  271. UserRepresentation userRepresentation = new UserRepresentation();
  272. userRepresentation.setUsername(user.getUsername());
  273. userRepresentation.setGroups(Collections.singletonList(user.getTenant()));
  274. userRepresentation.setEnabled(Boolean.TRUE);
  275. userRepresentation.setCredentials(user.getCredentials());
  276. userRepresentation.setFirstName(user.getName());
  277. if(Objects.nonNull(getUserIdByName(userRepresentation.getUsername()))){
  278. return SingleResponse.buildFailure("400","该用户名已存在!");
  279. }
  280. int status = realmResource.users().create(userRepresentation).getStatus();
  281. if(status != 201){
  282. return SingleResponse.buildFailure("400","账号创建失败!");
  283. }
  284. return SingleResponse.of(getUserIdByName(userRepresentation.getUsername()));
  285. }
  286. /**
  287. * 通过用户名获取用户id
  288. *
  289. * @param username
  290. * @return
  291. */
  292. private String getUserIdByName(String username){
  293. Optional<String> optional = realmResource.users().search(username)
  294. .stream().filter(user -> user.getUsername().equals(username))
  295. .map(UserRepresentation::getId)
  296. .findFirst();
  297. return optional.isEmpty()?null:optional.get();
  298. }
  299. @Override
  300. public Response updateUser(String userId, Object representation, Integer operateType) {
  301. UserResource userResource = realmResource.users().get(userId);
  302. UserRepresentation user = userResource.toRepresentation();
  303. switch (operateType) {
  304. case Constant.ENABLE:
  305. SwitchDTO switchDTO = (SwitchDTO) representation;
  306. user.setEnabled(switchDTO.getEnabled());
  307. break;
  308. case Constant.RESET_PASSWORD:
  309. CredentialRepresentation credential = (CredentialRepresentation) representation;
  310. user.setCredentials(Stream.of(credential).collect(Collectors.toList()));
  311. break;
  312. case Constant.RESET_ATTRIBUTE:
  313. UserRepresentation userRepresentation = (UserRepresentation) representation;
  314. user.setEmail(Optional.ofNullable(userRepresentation.getEmail()).orElse(null));
  315. user.setFirstName(userRepresentation.getFirstName());
  316. user.setAttributes(userRepresentation.getAttributes());
  317. break;
  318. case Constant.UPDATE_USER_FIRSTNAME:
  319. user.setFirstName((String) representation);
  320. break;
  321. default:
  322. break;
  323. }
  324. userResource.update(user);
  325. return SingleResponse.buildSuccess();
  326. }
  327. @Override
  328. public Response removeUser(String userId) {
  329. realmResource.users().get(userId).remove();
  330. return Response.buildSuccess();
  331. }
  332. @Override
  333. public Response regrouping(String userId, String groupId) {
  334. UserResource userResource = realmResource.users().get(userId);
  335. List<GroupRepresentation> groups = userResource.groups();
  336. // 移除
  337. groups.forEach(groupRepresentation-> userResource.leaveGroup(groupRepresentation.getId()));
  338. // 添加
  339. GroupsResource initGroups = realmResource.groups();
  340. List<String> targetGroups = Arrays.stream(initGroups.group(groupId).toRepresentation().getPath().split("/")).filter(Objects::nonNull).collect(Collectors.toList());
  341. getGroupId(targetGroups ,initGroups.groups()).forEach(userResource::joinGroup);
  342. return SingleResponse.buildSuccess();
  343. }
  344. private List<String> getGroupId(List<String> targetGroups , List<GroupRepresentation> groups){
  345. List<String> groupIds = Lists.newArrayList();
  346. GroupRepresentation group = groups.stream().filter(ele -> targetGroups.contains(ele.getName())).findFirst().get();
  347. groupIds.add(group.getId());
  348. if(!CollectionUtils.isEmpty(group.getSubGroups())){
  349. groupIds.addAll(getGroupId(targetGroups , group.getSubGroups()));
  350. }
  351. return groupIds;
  352. }
  353. @Override
  354. public Response roleMapping(UsersRoleMappingDTO usersRoleMappingDTO) {
  355. RoleScopeResource roleScopeResource = realmResource.users().get(usersRoleMappingDTO.getUserId()).roles().realmLevel();
  356. roleScopeResource.add(Optional.ofNullable(usersRoleMappingDTO.getAddRoleList()).orElse(Lists.newArrayList()));
  357. roleScopeResource.remove(Optional.ofNullable(usersRoleMappingDTO.getRemoveRoleList()).orElse(Lists.newArrayList()));
  358. return SingleResponse.buildSuccess();
  359. }
  360. @Override
  361. public Response queryUserCredentials(String userId) {
  362. return SingleResponse.of(realmResource.users().get(userId).credentials());
  363. }
  364. @Override
  365. public Response removeUserCredentials(String userId , String credentialId) {
  366. realmResource.users().get(userId).removeCredential(credentialId);
  367. return SingleResponse.buildSuccess();
  368. }
  369. @Override
  370. public Response addKeycloakTenant(GroupRepresentation groupRepresentation) {
  371. return SingleResponse.of(realmResource.groups().add(groupRepresentation).getDate());
  372. }
  373. @Override
  374. public Boolean isExitTargetRole(String userId ,String role) {
  375. List<String> roleList = realmResource.users().get(userId).roles().realmLevel().listAll()
  376. .stream().map(RoleRepresentation::getName).collect(Collectors.toList());
  377. return roleList.contains(role);
  378. }
  379. @Override
  380. @Cacheable(value = "msr:user:tenant", key = "#userId")
  381. public String queryUserTenant(String userId) {
  382. List<GroupRepresentation> groupList = realmResource.users().get(userId).groups()
  383. .stream()
  384. .sorted(Comparator.comparing(i -> i.getPath().length()))
  385. .collect(Collectors.toList());
  386. return CollectionUtils.isEmpty(groupList) ? "" : groupList.stream().findFirst().get().getPath();
  387. }
  388. @Override
  389. public Boolean addAttributesByUserId(String userId, String key, List<String> values) {
  390. UserResource userResource = realmResource.users().get(userId);
  391. UserRepresentation user = userResource.toRepresentation();
  392. Map<String, List<String>> attributes = Optional.ofNullable(user.getAttributes()).orElse(new HashMap<>());
  393. attributes.put(key ,values);
  394. user.setAttributes(attributes);
  395. userResource.update(user);
  396. return Boolean.TRUE;
  397. }
  398. @Override
  399. public PageResponse<UserRepresentation> getUserListByIds(SmsbDepartmentCmd departmentCmd , List<String> userId) {
  400. if(CollectionUtils.isEmpty(userId)){
  401. GroupResource groupResource = realmResource.groups()
  402. .group(realmResource.getGroupByPath(departmentCmd.getTenant()).getId());
  403. log.info("查询分页参数:first:{},max:{}",departmentCmd.getOffset() ,departmentCmd.getPageSize());
  404. return PageResponse.of(
  405. groupResource.members(departmentCmd.getOffset() ,departmentCmd.getPageSize())
  406. , groupResource.members().size() ,departmentCmd.getPageSize() ,departmentCmd.getPageIndex());
  407. }else{
  408. List<UserRepresentation> userRepresentations = realmResource.groups()
  409. .group(realmResource.getGroupByPath(departmentCmd.getTenant()).getId())
  410. .members()
  411. .stream()
  412. .filter(i -> userId.contains(i.getId()))
  413. .collect(Collectors.toList());
  414. return PageResponse.of(userRepresentations ,0 ,0,0);
  415. }
  416. }
  417. @Override
  418. @Cacheable(value = "msr:user:openIds", key = "#role")
  419. public List<String> queryWechatByRole(String role) {
  420. List<String> openIds = Lists.newArrayList();
  421. realmResource.roles().get(role).getRoleUserMembers().forEach(user->{
  422. Map<String, List<String>> attributes = user.getAttributes();
  423. if (attributes != null && attributes.get("wechat") != null) {
  424. openIds.addAll(attributes.get("wechat"));
  425. }
  426. });
  427. return openIds;
  428. }
  429. }