KeycloakServiceImpl.java 20 KB

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