本地缓存用户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: 新增角色-审查人员 `common.constant.EbtpRoleEnum`
- 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 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";
}

View File

@ -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)) {

View File

@ -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<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 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<EbtpUs
@Override
public EbtpUserInfoClient create(Throwable throwable) {
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.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<String, Object> 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<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
*/
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
*/