java B2B2C Springcloud仿淘寶電子商城系統- Zuul過濾器返回值攔截

Zuul作爲網關服務,是其他各服務對外中轉站,通過Zuul進行請求轉發。這就涉及到部分數據是不能原封返回的,比如服務之間通信的憑證,用戶的加密信息等等。
需要JAVA Spring Cloud大型企業分佈式微服務雲構建的B2B2C電子商務平臺源碼 壹零叄八柒柒肆六二六

舉個例子,用戶服務提供一個登錄接口,用戶名密碼正確後返回一個Token,此Token作爲用戶服務的通行證,那麼用戶登錄成功後返回的Token就需要進行加密或者防止篡改處理。在到達用戶服務其他接口前,就需要對Token進行校驗,非法的Token就不需要轉發到用戶服務中了,直接在網關層返回信息即可。

要修改服務返回的信息,需要使用的是Zuul的過濾器。使用時只需要繼承ZuulFilter,實現必要的方法即可。

Zuul提供默認的四種過濾器類型,通過filterType方法進行標識

pre:可以在請求被路由之前調用
route:在路由請求時候被調用
post:在route和error過濾器之後被調用
error:處理請求時發生錯誤時被調用

過濾器執行的順序是通過filterOrder方法進行排序,越小的值越優先處理。FilterConstants定義了一些列默認的過濾器的執行順序和路由類型,大部分需要用到的常量都在這兒。

例子中說明的,只有登錄接口需要攔截,所以只需要攔截登錄請求(/user/login)即可。可以通過過濾器的shouldFilter方法進行判斷是否需要攔截。

由於是在準發用戶服務成功後進行的數據修改,所以攔截器的類型時post類型的。整個類的實現如下:

public class AuthResponseFilter extends AbstractZuulFilter {

    private static final String RESPONSE_KEY_TOKEN = "token";
    @Value("${system.config.authFilter.authUrl}")
    private String authUrl;
    @Value("${system.config.authFilter.tokenKey}")
    private String tokenKey = RESPONSE_KEY_TOKEN;

    @Autowired
    private AuthApi authApi;

    @Override
    public boolean shouldFilter() {
        RequestContext context = getCurrentContext();
        return StringUtils.equals(context.getRequest().getRequestURI().toString(), authUrl);
    }

    @Override
    public Object run() {

        try {
            RequestContext context = getCurrentContext();

            InputStream stream = context.getResponseDataStream();
            String body = StreamUtils.copyToString(stream, Charset.forName("UTF-8"));

            if (StringUtils.isNotBlank(body)) {
                Gson gson = new Gson();
                @SuppressWarnings("unchecked")
                Map<String, String> result = gson.fromJson(body, Map.class);
                if (StringUtils.isNotBlank(result.get(tokenKey))) {
                    AuthModel authResult = authApi.encodeToken(result.get(tokenKey));
                    if (authResult.getStatus() != HttpServletResponse.SC_OK) {
                        throw new IllegalArgumentException(authResult.getErrMsg());
                    }
                    String accessToken = authResult.getToken();
                    result.put(tokenKey, accessToken);
                }
                body = gson.toJson(result);
            }
            context.setResponseBody(body);
        } catch (IOException e) {
            rethrowRuntimeException(e);
        }
        return null;
    }

    @Override
    public String filterType() {
        return FilterConstants.POST_TYPE;
    }

    @Override
    public int filterOrder() {
        return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 2;
    }

}

配置文件,中添加授權url和返回token的key:

system.config.authFilter.authUrl=/user/login 
system.config.authFilter.tokenKey=token 
context.setResponseBody(body)

這段代碼是核心,通過此方法修改返回數據。

當用戶登錄成功後,根據返回的token,通過授權服務進行token加密,這裏加密方式使用的是JWT。防止用戶篡改信息,非法的請求直接可以攔截在網關層。

關於Zuul過濾器的執行過程,這裏不需要多說明,源碼一看便知,ZuulServletFilter:

@Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        try {
            init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
            try {
                preRouting();
            } catch (ZuulException e) {
                error(e);
                postRouting();
                return;
            }

            // Only forward onto to the chain if a zuul response is not being sent
            if (!RequestContext.getCurrentContext().sendZuulResponse()) {
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }

            try {
                routing();
            } catch (ZuulException e) {
                error(e);
                postRouting();
                return;
            }
            try {
                postRouting();
            } catch (ZuulException e) {
                error(e);
                return;
            }
        } catch (Throwable e) {
            error(new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_FROM_FILTER_" + e.getClass().getName()));
        } finally {
            RequestContext.getCurrentContext().unset();
        }
    }

方法說明:
preRoute:執行pre類型的過濾器
postRoute:執行post類型的過濾器
route:執行route類型的過濾器
error:執行error類型的過濾器
通過context.setSendZuulResponse(false)可以終止請求的轉發,但是隻在pre類型的過濾器中設置纔可以。

java B2B2C 源碼 多級分銷springmvc mybatis多租戶電子商城系統

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章