本地缓存用户token

This commit is contained in:
fuqingji
2022-07-27 20:08:15 +08:00
parent 9d75d25d1e
commit 96c9961e8b
9 changed files with 220 additions and 23 deletions

View File

@ -13,3 +13,4 @@
- add: 文件sdk新增修改文件名称接口 `cloud.attachment.sdk.api.AttachmentClient` - add: 文件sdk新增修改文件名称接口 `cloud.attachment.sdk.api.AttachmentClient`
- add: 新增角色-审查人员 `common.constant.EbtpRoleEnum` - add: 新增角色-审查人员 `common.constant.EbtpRoleEnum`
- update-20220630-fuqj修改SpringSecurity过滤器中获取人员信息接口调用extend服务,extend服务实现在山分接口基础上扩展本地角色信息。 `cloud.security.starter.filter.TokenAuthenticationFilter` - update-20220630-fuqj修改SpringSecurity过滤器中获取人员信息接口调用extend服务,extend服务实现在山分接口基础上扩展本地角色信息。 `cloud.security.starter.filter.TokenAuthenticationFilter`
- update-20220727-fuqj修改获取人员信息逻辑把从山分查询出来的人员通过extend服务扩展覆盖后的信息缓存到本地redis中。![img.png](source/img.png)

BIN
source/img.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -9,11 +9,15 @@ public interface Constants {
public static final String TOKEN_PREFIX = "Bearer "; public static final String TOKEN_PREFIX = "Bearer ";
public static final String CURRENT_ROLE_CODE = "currentRoleCode"; public static final String CURRENT_ROLE_CODE = "currentRoleCode";
public static final String COOKIE_TOKEN_CODE = "mall3_token"; 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 TOKEN_EXPIRED = "90401";
public static final String REMOTE_ACCESS_FAILURE = "90500"; public static final String REMOTE_ACCESS_FAILURE = "90500";
String ACTUATOR_HEALTH = "actuator/health"; String ACTUATOR_HEALTH = "actuator/health";
String ACTUATOR_PROMETHEUS = "actuator/prometheus"; String ACTUATOR_PROMETHEUS = "actuator/prometheus";
String GET_USERINFO_API = "/v1/userinfo/get"; String GET_USERINFO_API = "/v1/userinfo/refresh";
} }

View File

@ -1,11 +1,11 @@
package com.chinaunicom.mall.ebtp.cloud.security.starter.filter; package com.chinaunicom.mall.ebtp.cloud.security.starter.filter;
import cn.hutool.core.bean.BeanUtil; 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.common.Constants;
import com.chinaunicom.mall.ebtp.cloud.security.starter.entity.AuthAllows; 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.RoleCodeAuthority;
import com.chinaunicom.mall.ebtp.cloud.security.starter.entity.SecurityUser; 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.cloud.userinfo.starter.service.UserInfoService;
import com.chinaunicom.mall.ebtp.common.base.entity.BaseCacheUser; import com.chinaunicom.mall.ebtp.common.base.entity.BaseCacheUser;
import lombok.extern.slf4j.Slf4j; 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 { public class TokenAuthenticationFilter extends OncePerRequestFilter {
@Autowired @Autowired
private UserInfoService client; private UserInfoService client;
@Autowired
private EbtpUserInfoClient ebtpClient;
@Autowired @Autowired
@ -101,6 +99,7 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
} catch (Exception e) { } catch (Exception e) {
request.getSession().setAttribute("code", e.getMessage()); request.getSession().setAttribute("code", e.getMessage());
ExceptionUtil.stacktraceToString(e);
log.error(e.getMessage()); log.error(e.getMessage());
} }
filterChain.doFilter(request, response); filterChain.doFilter(request, response);
@ -140,8 +139,8 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
*/ */
private Authentication getAuthentication(final String token, final String currentRoleCode, private Authentication getAuthentication(final String token, final String currentRoleCode,
final boolean isWhite) { final boolean isWhite) {
// BaseCacheUser userInfo = client.getUserInfo(token); BaseCacheUser userInfo = client.getUserInfo(token);
BaseCacheUser userInfo = ebtpClient.get(); // BaseCacheUser userInfo = ebtpClient.get();
log.debug("getUserInfo:{}", userInfo.toString()); log.debug("getUserInfo:{}", userInfo.toString());
// 对象为空, 则说明网络异常feign已熔断 // 对象为空, 则说明网络异常feign已熔断
if (Objects.isNull(userInfo)) { if (Objects.isNull(userInfo)) {

View File

@ -1,9 +1,9 @@
package com.chinaunicom.mall.ebtp.cloud.userinfo.starter.client; package com.chinaunicom.mall.ebtp.cloud.userinfo.starter.client;
import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.fallback.EbtpUserInfoClientFallbackFactory; 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.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) fallbackFactory = EbtpUserInfoClientFallbackFactory.class)
public interface EbtpUserInfoClient { public interface EbtpUserInfoClient {
@GetMapping("/v1/userinfo/get") /**
BaseCacheUser get(); * 刷新redis缓存的信息
*
* @return
*/
@PostMapping("/v1/userinfo/refresh")
public ResponseEntity<Boolean> refreshToken();
} }

View File

@ -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;
}

View File

@ -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;
}

View File

@ -3,6 +3,7 @@ package com.chinaunicom.mall.ebtp.cloud.userinfo.starter.fallback;
import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.client.EbtpUserInfoClient; import com.chinaunicom.mall.ebtp.cloud.userinfo.starter.client.EbtpUserInfoClient;
import feign.hystrix.FallbackFactory; import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Slf4j @Slf4j
@ -12,6 +13,6 @@ public class EbtpUserInfoClientFallbackFactory implements FallbackFactory<EbtpUs
@Override @Override
public EbtpUserInfoClient create(Throwable throwable) { public EbtpUserInfoClient create(Throwable throwable) {
log.error("EbtpUserInfoClient error : " + throwable.getMessage()); log.error("EbtpUserInfoClient error : " + throwable.getMessage());
return () -> null; return () -> ResponseEntity.ok(false);
} }
} }

View File

@ -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.AuthorityEntity;
import com.chinaunicom.mall.ebtp.cloud.security.starter.entity.SecurityEntity; 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.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.cloud.userinfo.starter.service.UserInfoService;
import com.chinaunicom.mall.ebtp.common.base.entity.BaseCacheUser; import com.chinaunicom.mall.ebtp.common.base.entity.BaseCacheUser;
import com.chinaunicom.mall.ebtp.common.util.JsonUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; 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.remoting.RemoteTimeoutException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.*;
import java.util.List; import java.util.concurrent.TimeUnit;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors; 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.*;
import static com.chinaunicom.mall.ebtp.cloud.security.starter.common.Constants.TOKEN_EXPIRED;
@Slf4j @Slf4j
@Service @Service
@ -29,9 +32,83 @@ public class UserInfoServiceImpl implements UserInfoService {
UnifastOAuthClient client; UnifastOAuthClient client;
// private @Autowired ObjectMapper userInfoObjectMapper; // private @Autowired ObjectMapper userInfoObjectMapper;
@Autowired(required = false)
@Qualifier("cacheRedisTemplate")
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private EbtpUserInfoClient ebtpClient;
@Override @Override
public BaseCacheUser getUserInfo(String token) { 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<Boolean> 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<String, String> userTable = JsonUtils.jsonToPojo(String.valueOf(extendRedis), Map.class);
//获取用户信息
List<CacheUser> 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<CacheRole> 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 * @return
*/ */
private BaseCacheUser convertToBusinessModel(SecurityEntity raw) { private BaseCacheUser convertToBusinessModel(SecurityEntity raw) {
log.debug("userinfo: {}", raw); log.info("userinfo: {}", raw);
// 对象为空, 则说明网络异常feign已熔断 // 对象为空, 则说明网络异常feign已熔断
if (Objects.isNull(raw)) { if (Objects.isNull(raw)) {
throw new RemoteTimeoutException(REMOTE_ACCESS_FAILURE); throw new RemoteTimeoutException(REMOTE_ACCESS_FAILURE);
@ -94,6 +171,8 @@ public class UserInfoServiceImpl implements UserInfoService {
} }
/** /**
* 获取用户信息
*
* @param token * @param token
* @return * @return
*/ */