ThreadLocal在拦截器中的使用
前置过滤捕获,写入context中,后置删除
每个request请求都有自己线程独享的数据,所以用到了ThreadLocal
1.添加拦截器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new IdentityInterceptor())
.addPathPatterns("/**");
}
}
2.拦截器定义
@Slf4j
@Component
public class IdentityInterceptor implements HandlerInterceptor {
/*
根据HttpHeader中的roleType判断用户身份
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
var identityStr = request.getHeader("roleType");
var loginContext = LoginContext.getLoginContext();
var pin = loginContext != null ? loginContext.getPin() : null;
Identity identity;
if (Strings.isNullOrEmpty(identityStr) ||
!Enums.getIfPresent(IdentityType.class, identityStr).isPresent()) {
log.warn("Identity:[{}] not found,use default identity instead.url:{}, User:{}", identityStr, request.getRequestURL(), pin);
identity = Identity.DEFAULT_IDENTITY;
} else {
identity = new Identity(identityStr);
}
Identity.setIdentity(identity); // 核心是这个,写入用户角色身份上下文
log.info("RoleType:[{}],user:[{}]-Identity:[{}] for url:{}. ", identityStr, pin, identity.getIdentityType(), request.getRequestURL());
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
log.info("remove Identity for [{}] from url {}"
, Identity.getIdentity() == null ? "null" : Identity.getIdentity().getIdentityType()
, request.getRequestURL());
Identity.remove(); // 删除用户角色上下文数据
}
}
3.Identity用户身份定义
package delta.service.session;
import com.alibaba.fastjson.JSON;
import com.jd.jsf.gd.util.RpcContext;
import org.apache.logging.log4j.util.Strings;
/**
* 用户身份信息
*
* @author zhoulun
* @date 2023-03-28 15:53
*/
public class Identity implements java.io.Serializable {
/**
* 序列化兼容
*/
private static final long serialVersionUID = 1L;
/**
* 用户身份属性在Session中的Key
*/
public static final String IDENTITY_CONTEXT_KEY = "delta-identity";
/**
* 用户身份 线程缓存
*/
private static final ThreadLocal<Identity> HOLDER = new ThreadLocal<>();
/**
* 默认构造函数
*
* @param identityTypeStr 用户身份类型
*/
public Identity(String identityTypeStr,String pin) {
//判断枚举项中是否存在该值
this.identityType = IdentityType.valueOf(identityTypeStr);
this.pin = pin;
}
/**
* 默认用户身份
*/
public static final Identity DEFAULT_IDENTITY = new Identity(IdentityType.COMMON_USER.name(),"AnonymousUser");
/**
* 用户身份类型
*/
private final IdentityType identityType;
/**
* 设置当前用户身份
*
* @param id 用户身份
*/
public static void setIdentity(Identity id) {
HOLDER.set(id);
//序列化为String再放Session中
RpcContext
.getContext()
.setSessionAttribute(
IDENTITY_CONTEXT_KEY,
JSON.toJSONString(id));
}
/**
* @return 获取当前用户身份
*/
public IdentityType getIdentityType() {
return identityType;
}
/** 用户pin */
private String pin;
public String getPin() {
return pin;
}
public void setPin(String pin) {
this.pin = pin;
}
/**
* 请求结束时清理用户身份信息
*/
public static void remove() {
HOLDER.remove();
RpcContext.getContext().clearSession();
}
/**
* @return 获取当前用户身份
*/
public static Identity getIdentity() {
Identity identity = HOLDER.get();
if (identity == null) {
String identityStr = (String) RpcContext.getContext().getSessionAttribute(IDENTITY_CONTEXT_KEY);
if (Strings.isNotEmpty(identityStr)) {
identity = JSON.parseObject(identityStr, Identity.class);
HOLDER.set(identity);
}
}
return identity;
}
@Override
public String toString() {
return "Identity{" +
"identityType=" + identityType +
", pin='" + pin + '\'' +
'}';
}
}
原创:做时间的朋友