All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.herodotus.engine.oauth2.authorization.definition.HerodotusRequestMatcher Maven / Gradle / Ivy

There is a newer version: 3.3.4.0
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2020-2030 郑庚伟 ZHENGGENGWEI (码匠君),  Licensed under the AGPL License
 *
 * This file is part of Herodotus Engine.
 *
 * Herodotus Engine is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Herodotus Engine is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 */

package cn.herodotus.engine.oauth2.authorization.definition;

import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.web.util.UrlPathHelper;

import java.io.Serializable;

/**
 * 

Description: 自定义 AntPathRequestMatcher

*

* 基于 AntPathRequestMatcher 代码,扩展了一些方法,解决原有 AntPathRequestMatcher 使用不方便问题。 * * @author : gengwei.zheng * @date : 2022/3/9 10:47 */ public final class HerodotusRequestMatcher implements RequestMatcher, Serializable { private static final Logger log = LoggerFactory.getLogger(HerodotusRequestMatcher.class); private static final String MATCH_ALL = "/**"; private Matcher matcher; private String pattern; private String httpMethod; private boolean caseSensitive; private boolean hasWildcard; private UrlPathHelper urlPathHelper; public HerodotusRequestMatcher() { } /** * Creates a matcher with the specific pattern which will match all HTTP methods in a * case sensitive manner. * * @param pattern the ant pattern to use for matching */ public HerodotusRequestMatcher(String pattern) { this(pattern, null); } public HerodotusRequestMatcher(HerodotusRequest request) { this(request.getPattern(), request.getHttpMethod()); } /** * Creates a matcher with the supplied pattern and HTTP method in a case sensitive * manner. * * @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. */ public HerodotusRequestMatcher(String pattern, String httpMethod) { this(pattern, httpMethod, true); } /** * 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 doesn't have the same method. * @param caseSensitive true if the matcher should consider case, else false */ public HerodotusRequestMatcher(String pattern, String httpMethod, boolean caseSensitive) { this(pattern, httpMethod, caseSensitive, null); } /** * 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 HerodotusRequestMatcher(String pattern, String httpMethod, boolean caseSensitive, UrlPathHelper urlPathHelper) { Assert.hasText(pattern, "Pattern cannot be null or empty"); this.caseSensitive = caseSensitive; this.hasWildcard = containSpecialCharacters(pattern); 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 = checkHttpMethod(httpMethod); this.urlPathHelper = urlPathHelper; } private String checkHttpMethod(String method) { if (StringUtils.isNotBlank(method)) { HttpMethod httpMethod = HttpMethod.valueOf(method); if (ObjectUtils.isNotEmpty(httpMethod)) { return httpMethod.name(); } } return null; } private boolean containSpecialCharacters(String source) { if (StringUtils.isNotBlank(source)) { return StringUtils.containsAny(source, new String[]{"*", "?", "{"}); } return false; } /** * 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 (StringUtils.isNotBlank(this.httpMethod) && StringUtils.isNotBlank(request.getMethod()) && !StringUtils.equalsIgnoreCase(this.httpMethod, request.getMethod())) { return false; } if (this.pattern.equals(MATCH_ALL)) { return true; } String url = getRequestPath(request); return this.matcher.matches(url); } public boolean matches(HerodotusRequest request) { if (StringUtils.isNotBlank(this.httpMethod) && StringUtils.isNotBlank(request.getHttpMethod()) && !StringUtils.equalsIgnoreCase(this.httpMethod, request.getHttpMethod())) { return false; } if (this.pattern.equals(MATCH_ALL)) { return true; } if (StringUtils.equals(getPattern(), request.getPattern())) { return true; } if (isHasWildcard() && !request.isHasWildcard()) { return this.matcher.matches(request.getPattern()); } if (!isHasWildcard() && request.isHasWildcard()) { Matcher matcher = new SpringAntMatcher(request.getPattern(), this.caseSensitive); return matcher.matches(getPattern()); } return false; } 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.isNotBlank(url) ? url + pathInfo : pathInfo; } return url; } public String getPattern() { return pattern; } public void setPattern(String pattern) { this.pattern = pattern; this.hasWildcard = containSpecialCharacters(this.pattern); } public String getHttpMethod() { return httpMethod; } public void setHttpMethod(String httpMethod) { this.httpMethod = httpMethod; } public boolean isHasWildcard() { return hasWildcard; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } HerodotusRequestMatcher that = (HerodotusRequestMatcher) o; return caseSensitive == that.caseSensitive && Objects.equal(pattern, that.pattern) && Objects.equal(httpMethod, that.httpMethod); } @Override public int hashCode() { return Objects.hashCode(pattern, httpMethod, caseSensitive); } @Override public String toString() { return MoreObjects.toStringHelper(this) .add("pattern", pattern) .add("httpMethod", httpMethod) .toString(); } private interface Matcher extends Serializable { boolean matches(String path); } private static final class SpringAntMatcher implements Matcher { private AntPathMatcher antMatcher; private String pattern; public SpringAntMatcher() { } private SpringAntMatcher(String pattern, boolean caseSensitive) { this.pattern = pattern; this.antMatcher = createMatcher(caseSensitive); } private static AntPathMatcher createMatcher(boolean caseSensitive) { AntPathMatcher matcher = new AntPathMatcher(); matcher.setTrimTokens(false); matcher.setCaseSensitive(caseSensitive); return matcher; } @Override public boolean matches(String path) { return this.antMatcher.match(this.pattern, path); } } /** * Optimized matcher for trailing wildcards */ private static final class SubPathMatcher implements Matcher { private String subPath; private int length; private boolean caseSensitive; public SubPathMatcher() { } private SubPathMatcher(String subPath, boolean caseSensitive) { Assert.isTrue(!subPath.contains("*"), "subpath cannot contain \"*\""); this.subPath = caseSensitive ? subPath : subPath.toLowerCase(); this.length = subPath.length(); this.caseSensitive = caseSensitive; } @Override public boolean matches(String path) { if (!this.caseSensitive) { path = path.toLowerCase(); } return path.startsWith(this.subPath) && (path.length() == this.length || path.charAt(this.length) == '/'); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy