dubbo 使用过滤器(filter)上下文传播用户信息

目录

1背景

在使用springboot + dubbo 微服务模式下,有多个微服务互相调用,有一些统一的数据需要获取,比如用户id等。
比如一个用户财务账号到账后需要调用信息服务通知用户,像用户id每个接口都需要,不需要作为方法参数显式传递,可以做统一处理隐式传参。

请求流程

2.如何实现

2.1整体处理流程

用户请求在网关处被 filter 拦截,获取请求的 token 查询到 UserId,将 UserId设置到 http请求header中。
在调用下游服务时 dubbo filter 拦截请求将http header中的 UserId设置到rpc请求的附属信息中。
下游服务从rpc请求的附属请求中获取到 UserId

2.2 实现细节

//网关拦截
@Slf4j
@WebFilter(filterName = "accessFilter", urlPatterns = {"/api/*"})
public class AccessFilter implements Filter {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
	
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;	
	String token = request.getHeader(Constants.TOKEN);
	String json = stringRedisTemplate.opsForValue().get(token);
	User user = JSON.parseObject(json, User.class);
	MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(request);

	mutableRequest.putHeader(Constants.USER_ID, user.getId());
	chain.doFilter(mutableRequest, servletResponse);	
    }
}

//包装http请求
public final class MutableHttpServletRequest extends HttpServletRequestWrapper {
    // holds custom header and value mapping
    private final Map<String, String> customHeaders;
 
    public MutableHttpServletRequest(HttpServletRequest request){
        super(request);
        this.customHeaders = new HashMap<String, String>();
    }
    
    public void putHeader(String name, String value){
        this.customHeaders.put(name, value);
    }
 
    public String getHeader(String name) {
        // check the custom headers first
        String headerValue = customHeaders.get(name);
        
        if (headerValue != null){
            return headerValue;
        }
        // else return from into the original wrapped object
        return ((HttpServletRequest) getRequest()).getHeader(name);
    }
 
    public Enumeration<String> getHeaderNames() {
        // create a set of the custom header names
        Set<String> set = new HashSet<String>(customHeaders.keySet());
        
        // now add the headers from the wrapped request object
        @SuppressWarnings("unchecked")
        Enumeration<String> e = ((HttpServletRequest) getRequest()).getHeaderNames();
        while (e.hasMoreElements()) {
            // add the names of the request headers into the list
            String n = e.nextElement();
            set.add(n);
        }
 
        // create an enumeration from the set and return
        return Collections.enumeration(set);
    }
}


//dubbo添加filter,如何实现请百度
@Slf4j
@Activate(group = CONSUMER)
public class ContextConsumerFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        RpcContext.getContext().setAttachment(Constants.USER_ID, AuthUtils.getUserId(Constants.USER_ID));
        return invoker.invoke(invocation);
    }
}

//封装如何获取当前用户id工具类
@Slf4j
@Component
public class AuthUtils {

    private static AuthUtils authUtils;

    @PostConstruct
    public void init() {
        authUtils = this;
    }

    public static Long getUserId() {
        Long userId = getContextId(Constants.USER_ID);
        if (userId == null) {
            throw new ServiceException("B0001", "获取上下文 userId 失败");
        }
        return userId;
    } 

    /**
     * 获取当前请求 request
     */
    public static HttpServletRequest getCurrentHttpRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        if (requestAttributes instanceof ServletRequestAttributes) {
            return ((ServletRequestAttributes) requestAttributes).getRequest();
        }

        return null;
    }

    /**
     * 从上下文中获取传递的ID
     *
     * @param key
     * @return
     */
    public static Long getContextId(String key) {
        HttpServletRequest request = getCurrentHttpRequest();
        if (request != null) {
            //web请求
            String contextId = request.getHeader(key);
            if (StringUtils.isNotEmpty(contextId)) {
                return Long.parseLong(contextId);
            }
        } else {
            Long contextId = (Long) RpcContext.getContext().getObjectAttachment(key);
            if (contextId != null) {
                return contextId;
            }
        }
        return null;
    }
}

//当前服务和下游服务都可以使用 AuthUtils.getUserId()直接获取用户od
posted @ 2023-05-06 15:05  meow_world  阅读(1565)  评论(0)    收藏  举报