zuul作為網關服務,是其他各服務對外中轉站,通過zuul進行請求轉發。這就涉及到部分數據是不能原封返回的,比如服務之間通信的憑證,用戶的加密信息等等。
舉個例子,用戶服務提供一個登錄接口,用戶名密碼正確后返回一個token,此token作為用戶服務的通行證,那么用戶登錄成功后返回的token就需要進行加密或者防止篡改處理。在到達用戶服務其他接口前,就需要對token進行校驗,非法的token就不需要轉發到用戶服務中了,直接在網關層返回信息即可。
要修改服務返回的信息,需要使用的是zuul的過濾器。使用時只需要繼承zuulfilter,實現必要的方法即可。
zuul提供默認的四種過濾器類型,通過filtertype方法進行標識
- pre:可以在請求被路由之前調用
- route:在路由請求時候被調用
- post:在route和error過濾器之后被調用
- error:處理請求時發生錯誤時被調用
過濾器執行的順序是通過filterorder方法進行排序,越小的值越優先處理。filterconstants定義了一些列默認的過濾器的執行順序和路由類型,大部分需要用到的常量都在這兒。
例子中說明的,只有登錄接口需要攔截,所以只需要攔截登錄請求(/user/login)即可。可以通過過濾器的shouldfilter方法進行判斷是否需要攔截。
由于是在準發用戶服務成功后進行的數據修改,所以攔截器的類型時post類型的。整個類的實現如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
@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類型的過濾器中設置才可以。
關于如何終止過濾器:
只有pre類型的過濾器支持終止轉發,其他過濾器都是按照順序執行的,而且pre類型的過濾器也只有在所有pre過濾器執行完后才可以終止轉發,做不到終止過濾器繼續執行。看zuulservletfilter源碼代碼:
1
2
3
4
5
|
// only forward onto to the chain if a zuul response is not being sent if (!requestcontext.getcurrentcontext().sendzuulresponse()) { filterchain.dofilter(servletrequest, servletresponse); return ; } |
本文中的代碼已提交至: https://gitee.com/cmlbeliever/springcloud 歡迎star
實現類在:api-getway工程下的com.cml.springcloud.api.filter.authresponsefilter
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/cml_blog/article/details/78349703