Chat filter + interceptor + JWT
One, foreword
I still remember that LAST time I wrote several articles about how to use JWT wechat Pay, Public account authorization + JWT, small program Authorization + JWT in actual projects.
Then, a friend asked me a question like this: Authorized useJWT issued tokenLater,Login and registrationEtc., the user isDon’t need a tokenIn this case, how to exclude the requested URL?
How to use “filter” or “blocker” to filter login and registration
Has anyone written this before?
In writing this article, I have thought of xiaobian onceSoa operationsLooking back at my own code, I laughed funny.
The Controller layer code is similar to this:
@RestController
public class LoginController {
@Resource
private HttpServletRequest request;
@Resource
private JwtUtil jwtUtil;
@apiOperation (value = "delete order interface based on order ID ")
@PostMapping(value = "/deleteById")
public RespResult deleteById(String id) {
String header = request.getHeader("token");// Get the header information. The key in the header is a token
if (StringUtils.isEmpty(header)) {
return new RespResult(400."Request header cannot be empty"); // A null header returns insufficient permissions
}
if(! header.startsWith("Bearer ")) { // As agreed with the front end, header values are Bearer + blank + JWT tokens
return new RespResult(400."Token error");// Header does not conform to the convention, return permission is insufficient
}
String token = header.substring(7); // Retrieve the token in the header
Claims claims = jwtUtil.parseJWT(token); // Decrypt the token using the JWT tool
if (claims == null) {
return new RespResult(400."Token verification failed");
}
// Call the service layer to delete the order
/ /... Is omitted
return new RespResult(200."Deleted successfully"); }}Copy the code
Lie CAO! Xiaobian this code can be really “crazy”, now only one interface, when there are dozens of interfaces, write dozens of times? Isn’t the code redundant? Besides, 8 hours a day, 7 hours in the copy and paste, I am afraid it is very sour…
Let’s talk about how to use filters or interceptors to kill redundant code.
Three, there is a filter why not
First of all, we need to use filters. We must first understand the principle of filters.
Filter
The Filter is inThe clientwithThe serverA filter between resource files that passes through before accessing themA series of filters (i.e., the filter chain)Proceed with the requestModify, judgeEtc., put the request that does not comply with the rule inIntercept or modify. Responses can also be filtered, blocked, or modified.As shown in the figure, the request made by the browser is first submitted to #A filter intoLine filtering, if the rules are met, the device is released and submitted to the next filter in the filter chain for filtering. The filter is in the chainThe order is related to the order in which it is configured in YML or config.
As you all know, the most important method in filter is the doFilter () method
In doFilter(), chain-.dofilter () is used to filter requests, and chain-.dofilter is used to filter response.
Let’s take a look at the order in which the filter chain code is executed:The picture is so easyChain. The doFilter () beforeTo filter the requested resources (eg:Verify login permissions and control resource access permissionsAfter chain.dofilter (), give some response to the front end, for example:{“code”: “6000”,”message”: “TOKEN validation failed “}
Let’s use filter to optimize the SAO code of xiaobian:
First, in the YML configuration file, set the URI that does not need to be filtered
filter:
config:
excludeUrls: /user/login,/user/register No filtering is required for login and registration
Copy the code
Next, write a filter: MyFilter
@Slf4j
@Order(1) // The smaller the number, the earlier this filter is executed
@Component
@WebFilter(filterName = "MyFilter", urlPatterns = {"/**"}) // Filter rules -- all
public class MyFilter implements Filter {
@Resource
private JwtUtils jwtUtils; // own JWT utility class
@Value("${filter.config.excludeUrls}")
private String excludeUrls; // Get the URI that does not need to be filtered in the configuration file
private List<String> excludes;
// Response message when token authentication fails
private static final String VALID_ERROR = "{\" code \ ": \" 6000 \ "and \" message \ ": \" TOKEN authentication failure \ "}";
@Override
public void init(FilterConfig filterConfig) {
/ / initialization
// Remove unfiltered URLS from the configuration file, before and after the string whitespace
excludes = Splitter.on(",").trimResults().splitToList(this.excludeUrls);
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String uri = request.getRequestURI(); // Get the request URI
String token = request.getHeader("token"); // Get the token in the header
try {
if (this.isExcludesUrl(uri)) { // Determine whether the request URI needs to be filtered (method below)
chain.doFilter(req, resp); // No, go ahead
} else {
if(! validateParams(token)) {// Verify the token in the header (method below)
response.getWriter().write(VALID_ERROR); // The authentication failed, and a verification failure message is returned
return;
}
chain.doFilter(request, resp); // The verification is successful}}catch (Exception ex) {
log.error("Exception error", ex);
response.getWriter().write(VALID_ERROR); // Throw an exception and return a validation failure message
} finally {
response.flushBuffer(); // Outputs buffered information to the page}}private boolean validateParams(String token) {
// Verify that it is null and that the format meets predefined requirements
if(! StringUtils.isEmpty(token) && token.startsWith("bearer ")) {
String token = token.substring(7);
Map<String, Object> map = jwtUtils.extractJwt(token); // Use the JWT decryption method
if(map ! =null) {
return true; // Decryption succeeded, return true}}return false; // Decryption failed, return false
}
private boolean isExcludesUrl(String path) {
for (String v : this.excludes) {
if (path.startsWith(v)) {// Check whether the request URI meets the uri requirements of the configuration file
return true; // If the request URI is login, register, return true}}return false; // If the request URI is not login or registration, return false}}Copy the code
Finally, we use Postman to empty request header access interface “” according to the order id delete order interface: localhost: 8080 / deleteById; The result is:
{
"code": 6000."message": "TOKEN verification failed"
}
Copy the code
In this way, a simple filter replaces the above “hot eye” operation and also excludes interfaces that do not require validation (login, registration, etc.). This is a real SAO…
Four, there are interceptors why not use
Come on, let’s have a lookPrinciple of interceptor; Interceptor, used in ASPect-oriented Programming in AOPA method or fieldIntercept before being accessed and then add some action before or after.Interception is an implementation strategy of AOP.
He has three methods:
Pre-processing, post-processing (Service is called and ModelAndView is returned, but page rendering is not carried out), and return processing (the page has been rendered) are implemented respectively.
- In preHandle, coding, security controls, and so on can be done before operation;
- In postHandle, there is an opportunity to modify the ModelAndView to be processed after the operation;
- AfterCompletion, you can determine whether an exception occurs and log it based on whether ex is null.
Let’s use the interceptor again and optimize the SAO code:
First, write the interceptor configuration file class:
/** * Create By CodeCow on 2020/7/26. */
public class MyInterceptorConfig extends WebMvcConfigurationSupport {
@Resource
private MyInterceptor myInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// Register an interceptor, declaring the interceptor object and the request to intercept
registry.addInterceptor(myInterceptor)
.addPathPatterns("/ * *") // All paths are blocked
.excludePathPatterns("/user/login") // Exclude user login requests
.excludePathPatterns("/user/register"); // Exclude user registration requests}}Copy the code
Next, write the interceptor implementation class
@Component
public class MyInterceptor implements HandlerInterceptor {
@Resource
private JwtUtils jwtUtils;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String headToken = request.getHeader("token"); // Get the token in the header
// Verify that it is null and that the format meets predefined requirements
if(! StringUtils.isEmpty(headToken) && headToken.startsWith("bearer ")) {
String token = headToken.substring(7);
Map<String, Object> map = jwtUtils.extractJwt(token); // Use the JWT decryption method
if(map ! =null) {
request.setAttribute("claims_map", map); // Put the JWT decrypted map into the request field
// Other operations omitted...
}
// Other operations omitted...
}
return true; }}Copy the code
Finally, when we need to use token, ** directly obtains “claims_map” ** from the request field.
In this way, a simple Interceptor also replaces the SAO operation.
Five, the afterword.
Filters and interceptors with JWT are simple and practical. How to choose a filter and interceptor in a practical project depends on your personal preference and programming style
The principles of both filters and interceptors are pretty much the same. If you understand their principles, you can get only one filter and one Interceptor.
Painted painted painted u recommend
-
Two years, just know how to implement multithreading, ah
-
Promise me no more if/else validation of request parameters, okay
-
Wechat mini program payment + public account payment (including source code)
-
Wechat official account authorization + access to user information + JWT login (source code included)
-
Wechat mini program authorization + obtaining user’s mobile phone number + JWT login (source included)
★★ whisper BB ★★
- Chinese traditional culture, first carefully, if useful, and then click “like” or “collect”, give yourself a little time to think
- If you don’t understand, you can leave a comment or write a private letter to make up, and make up will reply to ^_^ in the first time
- More humorous, witty articles, all in the “CodeCow· program cow” public account
“Java is like the sea, learn to make a boat, sailing on the sea, know the breadth of Java”