In the previous example, we used zuul to build a gateway //www.VeVB.COM/article/133235.htm
I won’t go into details about the role of gateways here. Our focus today is zuul’s Filter. Through Filter, we can implement security control, for example, only clients with username and password in the request parameters can access the server's resources. So how to implement Filter?
To implement Filter, the following steps are required:
1. Inherit the ZuulFilter class. In order to verify the characteristics of the Filter, we create 3 Filters here.
Filter by username
package com.chhliu.springcloud.zuul; import javax.servlet.http.HttpServletRequest; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; public class AccessUserNameFilter extends ZuulFilter { @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); System.out.println(String.format("%s AccessUserNameFilter request to %s", request.getMethod(), request.getRequestURL().toString())); String username = request.getParameter("username");// Get the requested parameter if(null != username && username.equals("chhliu")) {// If the requested parameter is not empty and the value is chhliu, then use ctx.setSendZuulResponse(true);// ctx.setResponseStatusCode(200); ctx.set("isSuccess", true);// Set the value to let the next Filter see the status of the previous Filter return null; }else{ ctx.setSendZuulResponse(false);// Filter the request and do not route it ctx.setResponseStatusCode(401);// Return the error code ctx.setResponseBody("{/"result/":/"username is not correct!/"}");// Return the error content ctx.set("isSuccess", false); return null; } } @Override public boolean shouldFilter() { return true;// Whether to execute the filter, it is true here, indicating that filtering is required} @Override public int filterOrder() { return 0;// The priority is 0, the larger the number, the lower the priority} @Override public String filterType() { return "pre";// Pre-filter} } By inheriting ZuulFilter and overwriting the above 4 methods, you can implement a simple filter. The following is a description of the relevant points of attention.
filterType: Returns a string representing the type of the filter. Four filter types with different life cycles are defined in zuul, as follows:
Zuul's main request lifecycle includes stages such as "pre", "route" and "post". For each request, all filters with these types are run.
filterOrder: defines the execution order of filters through int value
shouldFilter: Returns a boolean type to determine whether the filter is to be executed, so this function can implement the switch of the filter. In the above example, we directly return true, so the filter always takes effect
run: The specific logic of the filter. It should be noted that here we use ctx.setSendZuulResponse(false) to filter the request, and do not route it, and then set the error code it returns through ctx.setResponseStatusCode(401).
Coordination between filters
There is no direct way for filters to access each other. They can use RequestContext to share state, which is a Map-like structure with some explicit accessor methods for primitives considered Zuul. They are internally implemented using ThreadLocal. Interested students can check the source code.
Create another filter and filter according to the password:
package com.chhliu.springcloud.zuul; import javax.servlet.http.HttpServletRequest; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; public class AccessPasswordFilter extends ZuulFilter { @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); System.out.println(String.format("%s AccessPasswordFilter request to %s", request.getMethod(), request.getRequestURL().toString())); String username = request.getParameter("password"); if(null != username && username.equals("123456")) { ctx.setSendZuulResponse(true); ctx.setResponseStatusCode(200); ctx.set("isSuccess", true); return null; }else{ ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(401); ctx.setResponseBody("{/"result/":/"password is not correct!/"}"); ctx.set("isSuccess", false); return null; } } @Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); return (boolean) ctx.get("isSuccess");// If the result of the previous filter is true, it means that the previous filter has been successful and needs to enter the current filter. If the result of the previous filter is false, it means that the previous filter has not been successful. There is no need to perform the following filtering action. Skip all subsequent filters and return the result} @Override public int filterOrder() { return 1; // Priority set to 1 } @Override public String filterType() { return "pre"; } } Create a post filter at the end
package com.chhliu.springcloud.zuul; import javax.servlet.http.HttpServletRequest; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; public class AccessTokenFilter extends ZuulFilter { @Override public Object run() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); System.out.println(String.format("%s AccessTokenFilter request to %s", request.getMethod(), request.getRequestURL().toString())); ctx.setSendZuulResponse(true); ctx.setResponseStatusCode(200); ctx.setResponseBody("{/"name/":/"chhliu/"}");// Output the final result return null; } @Override public boolean shouldFilter() { return true; } @Override public int filterOrder() { return 0; } @Override public String filterType() { return "post";// After the request is processed, the filter will be entered} } 2. In the main class, first turn on the first two filters
@Bean public AccessUserNameFilter accessUserNameFilter() { return new AccessUserNameFilter(); } @Bean public AccessPasswordFilter accessPasswordFilter(){ return new AccessPasswordFilter(); } 3. Enter the request and verify
(1) The request is: http://localhost:8768/h2service/user/1?username=chhliu
The test result is: {"result":"password is not correct!"}
Console printing results
GET AccessUserNameFilter request to http://localhost:8768/h2service/user/1
GET AccessPasswordFilter request to http://localhost:8768/h2service/user/1
Passed AccessUserNameFilter filter, failed when verifying AccessPasswordFilter filter
There is no SQL printing in the background, which means that the request is not routed
(2) The request is: http://localhost:8768/h2service/user/1?password=123456
The test result is: {"result":"username is not correct!"}
Console printing results:
GET AccessUserNameFilter request to http://localhost:8768/h2service/user/1
It means that the AccessUserNameFilter filter has been reached, but the AccessPasswordFilter filter has not been reached. Because the AccessUserNameFilter filter has higher priority, it will be executed first. When executing, it is found that the filter conditions do not meet, so all the filters afterwards are skipped and the result is returned without SQL printing in the background, indicating that the request has not been routed.
(3) The request is: http://localhost:8768/h2service/user/1?password=123456&username=chhliu
The test results are:
{
"id": 1,
"username": "user1",
"name": "Zhang San",
"age": 20,
"balance": 100.00
}
The results of the console printing:
GET AccessUserNameFilter request to http://localhost:8768/h2service/user/1
GET AccessPasswordFilter request to http://localhost:8768/h2service/user/1
This means that the AccessUserNameFilter is executed first and then the AccessPasswordFilter is executed. This is consistent with the smaller the order value we mentioned earlier, the higher the priority.
The service requested at the same time has SQL output:
Hibernate: select user0_.id as id1_0_0_, user0_.age as age2_0_0_, user0_.balance as balance3_0_0_, user0_.name as name4_0_0_, user0_.username as username5_0_0_ from user user0_ where user0_.id=?
Indicates that the request was routed.
4. Turn on the post filter and run it again
Test result: The post filter was found to be last executed, although its priority is 0
Regarding the life cycle of zuul's Filter, see the figure below
Note: There is a small error in the picture above, routing should be route
5. Expand
zuul also provides a special type of filter, namely: StaticResponseFilter and SurgicalDebugFilter
StaticResponseFilter: StaticResponseFilter allows the generation of responses from Zuul itself, rather than forwarding the request to the source.
SurgicalDebugFilter: SurgicalDebugFilter allows routing specific requests to a delimited debug cluster or host.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.