diff --git a/README.md b/README.md index ebae60a..bb7c47f 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,5 @@ - add: kafka日志发送service添加@Async注解 `common.log.producer.OperationLogKafkaProducer` - add: 文件sdk新增修改文件名称接口 `cloud.attachment.sdk.api.AttachmentClient` - add: 新增角色-审查人员 `common.constant.EbtpRoleEnum` - - update-20220630-fuqj:修改SpringSecurity过滤器中获取人员信息接口,调用extend服务,extend服务实现在山分接口基础上扩展本地角色信息。 `cloud.security.starter.filter.TokenAuthenticationFilter` \ No newline at end of file + - update-20220630-fuqj:修改SpringSecurity过滤器中获取人员信息接口,调用extend服务,extend服务实现在山分接口基础上扩展本地角色信息。 `cloud.security.starter.filter.TokenAuthenticationFilter` + - update-20220727-fuqj:修改获取人员信息逻辑,把从山分查询出来的人员通过extend服务扩展覆盖后的信息,缓存到本地redis中。![img.png](source/img.png) \ No newline at end of file diff --git a/source/img.png b/source/img.png new file mode 100644 index 0000000..5d183fe Binary files /dev/null and b/source/img.png differ diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/security/starter/common/Constants.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/security/starter/common/Constants.java index b9173e7..401623b 100644 --- a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/security/starter/common/Constants.java +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/security/starter/common/Constants.java @@ -9,11 +9,15 @@ public interface Constants { public static final String TOKEN_PREFIX = "Bearer "; public static final String CURRENT_ROLE_CODE = "currentRoleCode"; public static final String COOKIE_TOKEN_CODE = "mall3_token"; + public static final String REDIS_USER_KEY = "ebtp:user_cache:"; + public static final String REDIS_USER_KEY_EXTEND = "ebtp:user_cache_extend"; + public static final String USERS = "users"; + public static final String ROLES = "roles"; public static final String TOKEN_EXPIRED = "90401"; public static final String REMOTE_ACCESS_FAILURE = "90500"; String ACTUATOR_HEALTH = "actuator/health"; String ACTUATOR_PROMETHEUS = "actuator/prometheus"; - String GET_USERINFO_API = "/v1/userinfo/get"; + String GET_USERINFO_API = "/v1/userinfo/refresh"; } diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/security/starter/filter/TokenAuthenticationFilter.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/security/starter/filter/TokenAuthenticationFilter.java index fb9adce..b43e66b 100644 --- a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/security/starter/filter/TokenAuthenticationFilter.java +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/security/starter/filter/TokenAuthenticationFilter.java @@ -1,11 +1,11 @@ package com.chinaunicom.mall.ebtp.cloud.security.starter.filter; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.exceptions.ExceptionUtil; import com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants; import com.chinaunicom.mall.ebtp.cloud.security.starter.entity.AuthAllows; import com.chinaunicom.mall.ebtp.cloud.security.starter.entity.RoleCodeAuthority; import com.chinaunicom.mall.ebtp.cloud.security.starter.entity.SecurityUser; -import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.client.EbtpUserInfoClient; import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.service.UserInfoService; import com.chinaunicom.mall.ebtp.common.base.entity.BaseCacheUser; import lombok.extern.slf4j.Slf4j; @@ -40,8 +40,6 @@ import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants. public class TokenAuthenticationFilter extends OncePerRequestFilter { @Autowired private UserInfoService client; - @Autowired - private EbtpUserInfoClient ebtpClient; @Autowired @@ -101,6 +99,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { } catch (Exception e) { request.getSession().setAttribute("code", e.getMessage()); + ExceptionUtil.stacktraceToString(e); log.error(e.getMessage()); } filterChain.doFilter(request, response); @@ -140,8 +139,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { */ private Authentication getAuthentication(final String token, final String currentRoleCode, final boolean isWhite) { -// BaseCacheUser userInfo = client.getUserInfo(token); - BaseCacheUser userInfo = ebtpClient.get(); + BaseCacheUser userInfo = client.getUserInfo(token); +// BaseCacheUser userInfo = ebtpClient.get(); log.debug("getUserInfo:{}", userInfo.toString()); // 对象为空, 则说明网络异常feign已熔断 if (Objects.isNull(userInfo)) { diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/client/EbtpUserInfoClient.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/client/EbtpUserInfoClient.java index b65f4d7..267630d 100644 --- a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/client/EbtpUserInfoClient.java +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/client/EbtpUserInfoClient.java @@ -1,9 +1,9 @@ package com.chinaunicom.mall.ebtp.cloud.userinfo.starter.client; import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.fallback.EbtpUserInfoClientFallbackFactory; -import com.chinaunicom.mall.ebtp.common.base.entity.BaseCacheUser; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; /** * 文档中心数据服务客户端 @@ -14,7 +14,11 @@ import org.springframework.web.bind.annotation.GetMapping; fallbackFactory = EbtpUserInfoClientFallbackFactory.class) public interface EbtpUserInfoClient { - @GetMapping("/v1/userinfo/get") - BaseCacheUser get(); - + /** + * 刷新redis缓存的信息 + * + * @return + */ + @PostMapping("/v1/userinfo/refresh") + public ResponseEntity refreshToken(); } diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/entity/CacheRole.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/entity/CacheRole.java new file mode 100644 index 0000000..5cad75b --- /dev/null +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/entity/CacheRole.java @@ -0,0 +1,46 @@ +package com.chinaunicom.mall.ebtp.cloud.userinfo.starter.entity; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 功能模块bean + * + * @author zyx + * + */ +@Data +@Accessors(chain = true) +@ApiModel +public class CacheRole implements Serializable { + + private static final Long serialVersionUID = 1L; + + /** + * 姓名 + */ + @ApiModelProperty(value = "角色") + private String role; + + /** + * 账号 + */ + @ApiModelProperty(value = "备注") + private String remarks; + + /** + * role_id + */ + @ApiModelProperty(value = "role_id") + private String roleId; + + /** + * 账号 + */ + @ApiModelProperty(value = "状态,0-默认") + private int status; +} diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/entity/CacheUser.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/entity/CacheUser.java new file mode 100644 index 0000000..399a100 --- /dev/null +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/entity/CacheUser.java @@ -0,0 +1,63 @@ +package com.chinaunicom.mall.ebtp.cloud.userinfo.starter.entity; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; + +/** + * 功能模块bean + * + * @author zyx + * + */ +@Data +@Accessors(chain = true) +@ApiModel +public class CacheUser implements Serializable { + + private static final Long serialVersionUID = 1L; + /** + * id + */ + @ApiModelProperty(value = "编号") + private String id; + + /** + * 姓名 + */ + @ApiModelProperty(value = "姓名") + private String name; + + /** + * 账号 + */ + @ApiModelProperty(value = "账号") + private String account; + + /** + * 密码 + */ + @ApiModelProperty(value = "密码") + private String password; + + /** + * 省份 + */ + @ApiModelProperty(value = "省份") + private String province; + + /** + * 角色 + */ + @ApiModelProperty(value = "角色") + private String role; + + /** + * 租户 + */ + @ApiModelProperty(value = "租户") + private String tenant; +} diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/fallback/EbtpUserInfoClientFallbackFactory.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/fallback/EbtpUserInfoClientFallbackFactory.java index 39734ab..9d7ab3d 100644 --- a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/fallback/EbtpUserInfoClientFallbackFactory.java +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/fallback/EbtpUserInfoClientFallbackFactory.java @@ -3,6 +3,7 @@ package com.chinaunicom.mall.ebtp.cloud.userinfo.starter.fallback; import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.client.EbtpUserInfoClient; import feign.hystrix.FallbackFactory; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @Slf4j @@ -12,6 +13,6 @@ public class EbtpUserInfoClientFallbackFactory implements FallbackFactory null; + return () -> ResponseEntity.ok(false); } } diff --git a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/service/impl/UserInfoServiceImpl.java b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/service/impl/UserInfoServiceImpl.java index 0a1d0df..c0739b6 100644 --- a/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/service/impl/UserInfoServiceImpl.java +++ b/uboot-common/src/main/java/com/chinaunicom/mall/ebtp/cloud/userinfo/starter/service/impl/UserInfoServiceImpl.java @@ -3,23 +3,26 @@ package com.chinaunicom.mall.ebtp.cloud.userinfo.starter.service.impl; import com.chinaunicom.mall.ebtp.cloud.security.starter.entity.AuthorityEntity; import com.chinaunicom.mall.ebtp.cloud.security.starter.entity.SecurityEntity; +import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.client.EbtpUserInfoClient; import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.client.UnifastOAuthClient; +import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.entity.CacheRole; +import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.entity.CacheUser; import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.service.UserInfoService; import com.chinaunicom.mall.ebtp.common.base.entity.BaseCacheUser; +import com.chinaunicom.mall.ebtp.common.util.JsonUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.http.ResponseEntity; import org.springframework.remoting.RemoteTimeoutException; -import org.springframework.security.access.AccessDeniedException; import org.springframework.stereotype.Service; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Optional; +import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.REMOTE_ACCESS_FAILURE; -import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.TOKEN_EXPIRED; +import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.*; @Slf4j @Service @@ -29,9 +32,83 @@ public class UserInfoServiceImpl implements UserInfoService { UnifastOAuthClient client; // private @Autowired ObjectMapper userInfoObjectMapper; + @Autowired(required = false) + @Qualifier("cacheRedisTemplate") + private RedisTemplate redisTemplate; + + @Autowired + private EbtpUserInfoClient ebtpClient; + @Override public BaseCacheUser getUserInfo(String token) { - return convertToBusinessModel(getAuthentication(token.replaceAll("Bearer ", ""))); + token = token.replaceAll(TOKEN_PREFIX, ""); + + Object o = redisTemplate.opsForValue().get(REDIS_USER_KEY + token); + if (o == null) { + return setLocalUserCache(token); + } + return (BaseCacheUser) o; + } + + /* + * 本地缓存token + */ + private BaseCacheUser setLocalUserCache(String token) { + + BaseCacheUser user = structureUser(token); + + redisTemplate.opsForValue().set(REDIS_USER_KEY + token, user, 30, TimeUnit.MINUTES); + + return user; + } + + /* + * 构建用户实体,查询extend缓存或服务覆盖用户信息。 + */ + private BaseCacheUser structureUser(String token) { + //查询山分用户信息 + BaseCacheUser user = convertToBusinessModel(getAuthentication(token)); + + //获取redis中extend的缓存 + Object extendRedis = redisTemplate.opsForValue().get(REDIS_USER_KEY_EXTEND); + if (extendRedis == null) { + //查extend库 刷新缓存 + ResponseEntity response = ebtpClient.refreshToken(); + if (response.getStatusCode().value() != 200 || Boolean.FALSE.equals(response.getBody())) { + log.info("获取extend服务的user缓存失败"); + } + extendRedis = redisTemplate.opsForValue().get(REDIS_USER_KEY_EXTEND); + } + + if (extendRedis == null) { + return user; + } + + Map userTable = JsonUtils.jsonToPojo(String.valueOf(extendRedis), Map.class); + //获取用户信息 + List users = JsonUtils.jsonToList(userTable.get(USERS), CacheUser.class); + CacheUser baseUser = users.stream().filter(u -> u.getAccount().equals(user.getLoginName())).findFirst().orElse(null); + if (Objects.isNull(baseUser)) { + return user; + } + + List roles = JsonUtils.jsonToList(userTable.get(ROLES), CacheRole.class); + user.setProvince(baseUser.getProvince()) + //覆盖角色 + .setAuthorityList( + Optional.of(roles + .stream() + .filter(r -> baseUser.getRole().contains(r.getRole())) + .map(br -> + new AuthorityEntity() + .setRoleId(br.getRoleId()) + .setRoleCode(br.getRole()) + .setRoleName(br.getRemarks()) + .setRoleScope("EBTP") + .setAuthorities(Collections.emptyList())) + .collect(Collectors.toList())) + .orElseGet(Collections::emptyList)); + return user; } /** @@ -41,7 +118,7 @@ public class UserInfoServiceImpl implements UserInfoService { * @return */ private BaseCacheUser convertToBusinessModel(SecurityEntity raw) { - log.debug("userinfo: {}", raw); + log.info("userinfo: {}", raw); // 对象为空, 则说明网络异常feign已熔断 if (Objects.isNull(raw)) { throw new RemoteTimeoutException(REMOTE_ACCESS_FAILURE); @@ -94,6 +171,8 @@ public class UserInfoServiceImpl implements UserInfoService { } /** + * 获取用户信息 + * * @param token * @return */ @@ -115,7 +194,7 @@ public class UserInfoServiceImpl implements UserInfoService { */ private List filterByEBTP(List list) { return Optional.ofNullable(list).map( - ls -> list.stream().filter(auth -> "EBTP".equals(auth.getRoleScope())).collect(Collectors.toList())) + ls -> list.stream().filter(auth -> "EBTP".equals(auth.getRoleScope())).collect(Collectors.toList())) .orElseGet(() -> list); }