合理使用gateWay过滤器,实现Concroller自动注入用户信息

        在日常开发中,经常我们需要在请求controller时传递用户信息。那么有没有一种方式可以让我们的程序在用户登录后自动向controller接口中注入用户用户信息呢?

       答案是yes!!!现在我们来看看博主当前的项目是如何实现的吧!

        1.首先登录时,账号密码校验通过后生成一个token,并将用户基本信息存入redis。将key返回给前端。

合理使用gateWay过滤器,实现Concroller自动注入用户信息_第1张图片

        2.前端收到后将当前用户的token缓存起来,每次像后台发请求时在header中携带token。

        3.重点来了,在gateway中添加一个过滤器,在过滤器中获取到tocken,用token作为键,去redis中获取用户的账号,以及诊所等基本信息。并将这些信息拼接到url后面。代码示例如下:

package com.lvyuanji.gateway.filter;

import cn.hutool.core.util.StrUtil;
import com.lvyuanji.account.api.service.IAccountAdminApiService;
import com.lvyuanji.common.consts.SystemConsts;
import com.lvyuanji.common.vo.redis.AccountEntity;
import com.lvyuanji.common.vo.redis.SalesmanLoginVo;
import com.lvyuanji.stock.api.service.ISalesmanApiService;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URI;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;


@Component
public class AccountRequestParameterGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {

    private static final Logger logger = LoggerFactory.getLogger(AccountRequestParameterGatewayFilterFactory.class);

    @Reference
    private IAccountAdminApiService accountAdminApiService;
    @Reference
    private ISalesmanApiService salesmanApiService;

    @Override
    public GatewayFilter apply(NameValueConfig config) {
        return new GatewayFilter() {
            @Override
            public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerHttpRequest request = exchange.getRequest();
                URI uri = request.getURI();
                StringBuilder query = new StringBuilder();
                String originalQuery = uri.getRawQuery();

                if (StringUtils.hasText(originalQuery)) {
                    query.append(originalQuery);
                    if (originalQuery.charAt(originalQuery.length() - 1) != '&') {
                        query.append('&');
                    }
                }

                String value = ServerWebExchangeUtils.expand(exchange, config.getValue());
                // TODO urlencode?
                query.append(config.getName());
                query.append('=');
                query.append(value);

                String method = request.getMethodValue();
                if ("GET".equals(method.toUpperCase())) {
                    logger.info("【GET】请求 URI:{} 参数:{}", uri.getPath(), query);
                }

                //获取redis中用户的缓存信息,拼接到请求参数后面
                HttpHeaders headers = exchange.getRequest().getHeaders();
                String token = headers.getFirst("token");
                if (StringUtils.hasText(token)) {
                    AccountEntity accountEntity = accountAdminApiService.loginAccountAdmin(token);
                    if (accountEntity != null) {
                        //先去header中获取诊所ID,如果没有去请求参数中获取
                        String tenantId = headers.getFirst("tenantId");
                        if (StringUtils.hasText(tenantId)) {
                            accountEntity.setTenantId(Long.valueOf(tenantId));
                        } else {
                            List tenantIds = request.getQueryParams().get("tenantId");
                            if (!CollectionUtils.isEmpty(tenantIds)) {
                                accountEntity.setTenantId(Long.valueOf(tenantIds.get(0)));
                            }
                        }
                        //封装其他参数
                        Map beanMap = beanValue(accountEntity);
                        if (!CollectionUtils.isEmpty(beanMap)) {
                            for (String key : beanMap.keySet()) {
                                try {
                                    Object obj = beanMap.get(key);
                                    String param = obj != null ? URLEncoder.encode(obj.toString(), "UTF-8") : null;
                                    query.append('&').append(key).append('=').append(param);
                                } catch (UnsupportedEncodingException e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    } else {
                        //获取应用类型
                        String appType = StrUtil.isNotEmpty(request.getHeaders().getFirst(SystemConsts.APP_TYPE)) ? request.getHeaders().getFirst(SystemConsts.APP_TYPE) : "";
                        if ("applets".equals(appType)) {
                            query.append("&").append("userType").append("=").append("SALESMAN");
                        }
                    }
                } else {
                    String tenantId = headers.getFirst("tenantId");
                    if (StringUtils.hasText(tenantId)) {

                        query.append('&').append("tenantId").append('=').append(tenantId);
                    }
                }

                try {
                    String queryStr = filterOperator(query.toString());
                    URI newUri = UriComponentsBuilder.fromUri(uri)
                            .replaceQuery(queryStr).build(true).toUri();
                    ServerHttpRequest req = exchange.getRequest().mutate().uri(newUri)
                            .build();

                    return chain.filter(exchange.mutate().request(req).build());
                } catch (RuntimeException ex) {
                    throw new IllegalStateException(
                            "Invalid URI query: \"" + query.toString() + "\"");
                }
            }

            @Override
            public String toString() {
                return filterToStringCreator(AccountRequestParameterGatewayFilterFactory.this)
                        .append(config.getName(), config.getValue()).toString();
            }
        };
    }

    /**
     * 过滤特殊字符
     *
     * @param target
     * @return
     */
    private String filterOperator(String target) {
        target = target.replace("[", "");
        return target.replace("]", "");
    }

    /**
     * 获取bean的属性和值
     *
     * @param bean
     * @return
     */
    private Map beanValue(AccountEntity bean) {
        Map result = new HashMap<>();
        Class clazz = bean.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            String name = field.getName();
            field.setAccessible(true);
            Object value = null;
            try {
                value = field.get(bean);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            if (value != null) {
                result.put(name, value);
            }
        }
        return result;
    }

}

        4.spring参数解析器会自动将url后面的参数解析为对应的AccountBean,这样我们在需要用到Account信息的Controller方法中只需要在参数中加入AccountBean参数即可,。前端也不必刻意传Account信息,因为Header中携带了Token。

合理使用gateWay过滤器,实现Concroller自动注入用户信息_第2张图片

       

你可能感兴趣的:(java,spring,boot)