SpringSecurity - 基础概念之 RequestMatcher
public final class AntPathRequestMatcher implements RequestMatcher, RequestVariablesExtractor {
private static final String MATCH_ALL = "/**";
private final Matcher matcher;
private final String pattern;
private final HttpMethod httpMethod;
private final boolean caseSensitive;
private final UrlPathHelper urlPathHelper;
// 利用面向对象的多态特性定义了几个构造器
/**
* Creates a matcher with the supplied pattern which will match the specified Http
* method
* @param pattern the ant pattern to use for matching
* @param httpMethod the HTTP method. The {@code matches} method will return false if
* the incoming request doesn't have the same method.
* @param caseSensitive true if the matcher should consider case, else false
* @param urlPathHelper if non-null, will be used for extracting the path from the
* HttpServletRequest
*/
public AntPathRequestMatcher(String pattern, String httpMethod, boolean caseSensitive,
UrlPathHelper urlPathHelper) {
Assert.hasText(pattern, "Pattern cannot be null or empty");
this.caseSensitive = caseSensitive;
if (pattern.equals(MATCH_ALL) || pattern.equals("**")) {
pattern = MATCH_ALL;
this.matcher = null;
}
else {
// If the pattern ends with {@code /**} and has no other wildcards or path
// variables, then optimize to a sub-path match
if (pattern.endsWith(MATCH_ALL)
&& (pattern.indexOf('?') == -1 && pattern.indexOf('{') == -1 && pattern.indexOf('}') == -1)
&& pattern.indexOf("*") == pattern.length() - 2) {
this.matcher = new SubpathMatcher(pattern.substring(0, pattern.length() - 3), caseSensitive);
}
else {
this.matcher = new SpringAntMatcher(pattern, caseSensitive);
}
}
this.pattern = pattern;
this.httpMethod = StringUtils.hasText(httpMethod) ? HttpMethod.valueOf(httpMethod) : null;
this.urlPathHelper = urlPathHelper;
}
/**
* Returns true if the configured pattern (and HTTP-Method) match those of the
* supplied request.
* @param request the request to match against. The ant pattern will be matched
* against the {@code servletPath} + {@code pathInfo} of the request.
*/
@Override
public boolean matches(HttpServletRequest request) {
if (this.httpMethod != null && StringUtils.hasText(request.getMethod())
&& this.httpMethod != valueOf(request.getMethod())) {
return false;
}
if (this.pattern.equals(MATCH_ALL)) {
return true;
}
String url = getRequestPath(request);
return this.matcher.matches(url);
}
...
@Override
public MatchResult matcher(HttpServletRequest request) {
if (this.matcher == null || !matches(request)) {
return MatchResult.notMatch();
}
String url = getRequestPath(request);
return MatchResult.match(this.matcher.extractUriTemplateVariables(url));
}
private String getRequestPath(HttpServletRequest request) {
if (this.urlPathHelper != null) {
return this.urlPathHelper.getPathWithinApplication(request);
}
String url = request.getServletPath();
String pathInfo = request.getPathInfo();
if (pathInfo != null) {
url = StringUtils.hasLength(url) ? url + pathInfo : pathInfo;
}
return url;
}
public String getPattern() {
return this.pattern;
}
// 重写了 hasCode、equals、toString 方法
// 定义了一个 Matcher 接口用于判断请求路径是否匹配,RequestMatcher 的入参是 HttpServletRequest
private interface Matcher {
boolean matches(String path);
Map<String, String> extractUriTemplateVariables(String path);
}
// 下面是两个 Matcher 的实现类,
private static final class SpringAntMatcher implements Matcher {
...
}
/**
* Optimized matcher for trailing wildcards
*/
private static final class SubpathMatcher implements Matcher {
...
}
}