java权限控制框架_spring mvc,框架实现权限控制

1 private UrlPathHelper urlPathHelper = newUrlPathHelper();2

3 private PathMatcher pathMatcher = newAntPathMatcher();4

5 private org.springframework.web.servlet.mvc.multiaction.MethodNameResolver methodNameResolver = neworg.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver();6

7 private final Map, ServletHandlerMethodResolver> methodResolverCache = new ConcurrentHashMap, ServletHandlerMethodResolver>(8 64);9

10 static classServletAnnotationMappingUtils {11

12 /**

13 * Check whether the given request matches the specified request14 * methods.15 *16 *@parammethods17 * the HTTP request methods to check against18 *@paramrequest19 * the current HTTP request to check20 */

21 public static booleancheckRequestMethod(RequestMethod[] methods, HttpServletRequest request) {22 String inputMethod =request.getMethod();23 if (ObjectUtils.isEmpty(methods) && !RequestMethod.OPTIONS.name().equals(inputMethod)) {24 return true;25 }26 for(RequestMethod method : methods) {27 if(method.name().equals(inputMethod)) {28 return true;29 }30 }31 return false;32 }33

34 /**

35 * Check whether the given request matches the specified parameter36 * conditions.37 *38 *@paramparams39 * the parameter conditions, following40 * {@linkorg.springframework.web.bind.annotation.RequestMapping#params()41 * RequestMapping.#params()}42 *@paramrequest43 * the current HTTP request to check44 */

45 public static booleancheckParameters(String[] params, HttpServletRequest request) {46 if (!ObjectUtils.isEmpty(params)) {47 for(String param : params) {48 int separator = param.indexOf('=');49 if (separator == -1) {50 if (param.startsWith("!")) {51 if (WebUtils.hasSubmitParameter(request, param.substring(1))) {52 return false;53 }54 } else if (!WebUtils.hasSubmitParameter(request, param)) {55 return false;56 }57 } else{58 boolean negated = separator > 0 && param.charAt(separator - 1) == '!';59 String key = !negated ? param.substring(0, separator) : param.substring(0, separator - 1);60 String value = param.substring(separator + 1);61 boolean match =value.equals(request.getParameter(key));62 if(negated) {63 match = !match;64 }65 if (!match) {66 return false;67 }68 }69 }70 }71 return true;72 }73

74 /**

75 * Check whether the given request matches the specified header76 * conditions.77 *78 *@paramheaders79 * the header conditions, following80 * {@linkorg.springframework.web.bind.annotation.RequestMapping#headers()81 * RequestMapping.headers()}82 *@paramrequest83 * the current HTTP request to check84 */

85 public static booleancheckHeaders(String[] headers, HttpServletRequest request) {86 if (!ObjectUtils.isEmpty(headers)) {87 for(String header : headers) {88 int separator = header.indexOf('=');89 if (separator == -1) {90 if (header.startsWith("!")) {91 if (request.getHeader(header.substring(1)) != null) {92 return false;93 }94 } else if (request.getHeader(header) == null) {95 return false;96 }97 } else{98 boolean negated = (separator > 0 && header.charAt(separator - 1) == '!');99 String key = !negated ? header.substring(0, separator) : header.substring(0, separator - 1);100 String value = header.substring(separator + 1);101 if(isMediaTypeHeader(key)) {102 List requestMediaTypes =MediaType.parseMediaTypes(request.getHeader(key));103 List valueMediaTypes =MediaType.parseMediaTypes(value);104 boolean found = false;105 for (Iterator valIter =valueMediaTypes.iterator(); valIter.hasNext()106 && !found;) {107 MediaType valueMediaType =valIter.next();108 for (Iterator reqIter =requestMediaTypes.iterator(); reqIter.hasNext()109 && !found;) {110 MediaType requestMediaType =reqIter.next();111 if(valueMediaType.includes(requestMediaType)) {112 found = true;113 }114 }115

116 }117 if(negated) {118 found = !found;119 }120 if (!found) {121 return false;122 }123 } else{124 boolean match =value.equals(request.getHeader(key));125 if(negated) {126 match = !match;127 }128 if (!match) {129 return false;130 }131 }132 }133 }134 }135 return true;136 }137

138 private static booleanisMediaTypeHeader(String headerName) {139 return ("Accept".equalsIgnoreCase(headerName) || "Content-Type".equalsIgnoreCase(headerName));140 }141

142 }143

144 /**

145 * Comparator capable of sorting {@linkRequestSpecificMappingInfo}s (RHIs)146 * so that sorting a list with this comparator will result in:147 *

  • 148 *
  • RHIs with149 * {@linkplainAnnotationMethodHandlerAdapter.RequestSpecificMappingInfo#matchedPatterns150 * better matched paths} take precedence over those with a weaker match (as151 * expressed by the {@linkplainPathMatcher#getPatternComparator(String)152 * path pattern comparator}.) Typically, this means that patterns without153 * wild cards and uri templates will be ordered before those without.154 *
  • RHIs with one single {@linkplainRequestMappingInfo#methods request155 * method} will be ordered before those without a method, or with more than156 * one method.157 *
  • RHIs with more {@linkplainRequestMappingInfo#params request158 * parameters} will be ordered before those with less parameters159 * 160 */

161 static class RequestSpecificMappingInfoComparator implements Comparator{162

163 private final ComparatorpathComparator;164

165 private finalServerHttpRequest request;166

167 RequestSpecificMappingInfoComparator(ComparatorpathComparator, HttpServletRequest request) {168 this.pathComparator =pathComparator;169 this.request = newServletServerHttpRequest(request);170 }171

172 @Override173 public intcompare(RequestSpecificMappingInfo info1, RequestSpecificMappingInfo info2) {174 int pathComparison =pathComparator.compare(info1.bestMatchedPattern(), info2.bestMatchedPattern());175 if (pathComparison != 0) {176 returnpathComparison;177 }178 int info1ParamCount =info1.getParamCount();179 int info2ParamCount =info2.getParamCount();180 if (info1ParamCount !=info2ParamCount) {181 return info2ParamCount -info1ParamCount;182 }183 int info1HeaderCount =info1.getHeaderCount();184 int info2HeaderCount =info2.getHeaderCount();185 if (info1HeaderCount !=info2HeaderCount) {186 return info2HeaderCount -info1HeaderCount;187 }188 int acceptComparison =compareAcceptHeaders(info1, info2);189 if (acceptComparison != 0) {190 returnacceptComparison;191 }192 int info1MethodCount =info1.getMethodCount();193 int info2MethodCount =info2.getMethodCount();194 if (info1MethodCount == 0 && info2MethodCount > 0) {195 return 1;196 } else if (info2MethodCount == 0 && info1MethodCount > 0) {197 return -1;198 } else if (info1MethodCount == 1 & info2MethodCount > 1) {199 return -1;200 } else if (info2MethodCount == 1 & info1MethodCount > 1) {201 return 1;202 }203 return 0;204 }205

206 private intcompareAcceptHeaders(RequestMappingInfo info1, RequestMappingInfo info2) {207 List requestAccepts =request.getHeaders().getAccept();208 MediaType.sortByQualityValue(requestAccepts);209

210 List info1Accepts =getAcceptHeaderValue(info1);211 List info2Accepts =getAcceptHeaderValue(info2);212

213 for(MediaType requestAccept : requestAccepts) {214 int pos1 =indexOfIncluded(info1Accepts, requestAccept);215 int pos2 =indexOfIncluded(info2Accepts, requestAccept);216 if (pos1 !=pos2) {217 return pos2 -pos1;218 }219 }220 return 0;221 }222

223 private int indexOfIncluded(ListinfoAccepts, MediaType requestAccept) {224 for (int i = 0; i < infoAccepts.size(); i++) {225 MediaType info1Accept =infoAccepts.get(i);226 if(requestAccept.includes(info1Accept)) {227 returni;228 }229 }230 return -1;231 }232

233 private ListgetAcceptHeaderValue(RequestMappingInfo info) {234 for(String header : info.headers) {235 int separator = header.indexOf('=');236 if (separator != -1) {237 String key = header.substring(0, separator);238 String value = header.substring(separator + 1);239 if ("Accept".equalsIgnoreCase(key)) {240 returnMediaType.parseMediaTypes(value);241 }242 }243 }244 returnCollections.emptyList();245 }246 }247

248 /**

249 * Subclass of {@linkRequestMappingInfo} that holds request-specific data.250 */

251 static class RequestSpecificMappingInfo extendsRequestMappingInfo {252

253 private final List matchedPatterns = new ArrayList();254

255 RequestSpecificMappingInfo(String[] patterns, RequestMethod[] methods, String[] params, String[] headers) {256 super(patterns, methods, params, headers);257 }258

259 RequestSpecificMappingInfo(RequestMappingInfo other) {260 super(other.patterns, other.methods, other.params, other.headers);261 }262

263 public voidaddMatchedPattern(String matchedPattern) {264 matchedPatterns.add(matchedPattern);265 }266

267 public void sortMatchedPatterns(ComparatorpathComparator) {268 Collections.sort(matchedPatterns, pathComparator);269 }270

271 publicString bestMatchedPattern() {272 return (!this.matchedPatterns.isEmpty() ? this.matchedPatterns.get(0) : null);273 }274 }275

276 /**

277 * Holder for request mapping metadata.278 */

279 static classRequestMappingInfo {280

281 private finalString[] patterns;282

283 private finalRequestMethod[] methods;284

285 private finalString[] params;286

287 private finalString[] headers;288

289 RequestMappingInfo(String[] patterns, RequestMethod[] methods, String[] params, String[] headers) {290 this.patterns = (patterns != null ? patterns : new String[0]);291 this.methods = (methods != null ? methods : new RequestMethod[0]);292 this.params = (params != null ? params : new String[0]);293 this.headers = (headers != null ? headers : new String[0]);294 }295

296 public booleanhasPatterns() {297 return (this.patterns.length > 0);298 }299

300 publicString[] getPatterns() {301 return this.patterns;302 }303

304 public intgetMethodCount() {305 return this.methods.length;306 }307

308 public intgetParamCount() {309 return this.params.length;310 }311

312 public intgetHeaderCount() {313 return this.headers.length;314 }315

316 public booleanmatches(HttpServletRequest request) {317 return matchesRequestMethod(request) && matchesParameters(request) &&matchesHeaders(request);318 }319

320 public booleanmatchesHeaders(HttpServletRequest request) {321

322 return ServletAnnotationMappingUtils.checkHeaders(this.headers, request);323 }324

325 public booleanmatchesParameters(HttpServletRequest request) {326 return ServletAnnotationMappingUtils.checkParameters(this.params, request);327 }328

329 public booleanmatchesRequestMethod(HttpServletRequest request) {330 return ServletAnnotationMappingUtils.checkRequestMethod(this.methods, request);331 }332

333 public SetmethodNames() {334 Set methodNames = new LinkedHashSet(this.methods.length);335 for (RequestMethod method : this.methods) {336 methodNames.add(method.name());337 }338 returnmethodNames;339 }340

341 @Override342 public booleanequals(Object obj) {343 RequestMappingInfo other =(RequestMappingInfo) obj;344 return (Arrays.equals(this.patterns, other.patterns) && Arrays.equals(this.methods, other.methods)345 && Arrays.equals(this.params, other.params) && Arrays.equals(this.headers, other.headers));346 }347

348 @Override349 public inthashCode() {350 return (Arrays.hashCode(this.patterns) * 23 + Arrays.hashCode(this.methods) * 29

351 + Arrays.hashCode(this.params) * 31 + Arrays.hashCode(this.headers));352 }353

354 @Override355 publicString toString() {356 StringBuilder builder = newStringBuilder();357 builder.append(Arrays.asList(this.patterns));358 if (this.methods.length > 0) {359 builder.append(',');360 builder.append(Arrays.asList(this.methods));361 }362 if (this.headers.length > 0) {363 builder.append(',');364 builder.append(Arrays.asList(this.headers));365 }366 if (this.params.length > 0) {367 builder.append(',');368 builder.append(Arrays.asList(this.params));369 }370 returnbuilder.toString();371 }372 }373

374 /**

375 * Servlet-specific subclass of {@codeHandlerMethodResolver}.376 */

377 @SuppressWarnings("deprecation")378 private classServletHandlerMethodResolver379 extendsorg.springframework.web.bind.annotation.support.HandlerMethodResolver {380

381 private final Map mappings = new HashMap();382

383 private ServletHandlerMethodResolver(Class>handlerType) {384 init(handlerType);385 }386

387 @Override388 protected booleanisHandlerMethod(Method method) {389 if (this.mappings.containsKey(method)) {390 return true;391 }392 RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);393 if (mapping != null) {394 String[] patterns =mapping.value();395 RequestMethod[] methods = new RequestMethod[0];396 String[] params = new String[0];397 String[] headers = new String[0];398 if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) {399 methods =mapping.method();400 }401 if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) {402 params =mapping.params();403 }404 if (!hasTypeLevelMapping() || !Arrays.equals(mapping.headers(), getTypeLevelMapping().headers())) {405 headers =mapping.headers();406 }407 RequestMappingInfo mappingInfo = newRequestMappingInfo(patterns, methods, params, headers);408 this.mappings.put(method, mappingInfo);409 return true;410 }411 return false;412 }413

414 public Method resolveHandlerMethod(HttpServletRequest request) throwsServletException {415 String lookupPath =urlPathHelper.getLookupPathForRequest(request);416 Comparator pathComparator =pathMatcher.getPatternComparator(lookupPath);417 Map targetHandlerMethods = new LinkedHashMap();418 Set allowedMethods = new LinkedHashSet(7);419 String resolvedMethodName = null;420 for(Method handlerMethod : getHandlerMethods()) {421 RequestSpecificMappingInfo mappingInfo = newRequestSpecificMappingInfo(422 this.mappings.get(handlerMethod));423 boolean match = false;424 if(mappingInfo.hasPatterns()) {425 for(String pattern : mappingInfo.getPatterns()) {426 if (!hasTypeLevelMapping() && !pattern.startsWith("/")) {427 pattern = "/" +pattern;428 }429 String combinedPattern =getCombinedPattern(pattern, lookupPath, request);430 if (combinedPattern != null) {431 if(mappingInfo.matches(request)) {432 match = true;433 mappingInfo.addMatchedPattern(combinedPattern);434 } else{435 if (!mappingInfo.matchesRequestMethod(request)) {436 allowedMethods.addAll(mappingInfo.methodNames());437 }438 break;439 }440 }441 }442 mappingInfo.sortMatchedPatterns(pathComparator);443 } else if(useTypeLevelMapping(request)) {444 String[] typeLevelPatterns =getTypeLevelMapping().value();445 for(String typeLevelPattern : typeLevelPatterns) {446 if (!typeLevelPattern.startsWith("/")) {447 typeLevelPattern = "/" +typeLevelPattern;448 }449 boolean useSuffixPattern =useSuffixPattern(request);450 if (getMatchingPattern(typeLevelPattern, lookupPath, useSuffixPattern) != null) {451 if(mappingInfo.matches(request)) {452 match = true;453 mappingInfo.addMatchedPattern(typeLevelPattern);454 } else{455 if (!mappingInfo.matchesRequestMethod(request)) {456 allowedMethods.addAll(mappingInfo.methodNames());457 }458 break;459 }460 }461 }462 mappingInfo.sortMatchedPatterns(pathComparator);463 } else{464 //No paths specified: parameter match sufficient.

465 match =mappingInfo.matches(request);466 if (match && mappingInfo.getMethodCount() == 0 && mappingInfo.getParamCount() == 0

467 && resolvedMethodName != null && !resolvedMethodName.equals(handlerMethod.getName())) {468 match = false;469 } else{470 if (!mappingInfo.matchesRequestMethod(request)) {471 allowedMethods.addAll(mappingInfo.methodNames());472 }473 }474 }475 if(match) {476 Method oldMappedMethod =targetHandlerMethods.put(mappingInfo, handlerMethod);477 if (oldMappedMethod != null && oldMappedMethod !=handlerMethod) {478 if (methodNameResolver != null && !mappingInfo.hasPatterns()) {479 if (!oldMappedMethod.getName().equals(handlerMethod.getName())) {480 if (resolvedMethodName == null) {481 resolvedMethodName =methodNameResolver.getHandlerMethodName(request);482 }483 if (!resolvedMethodName.equals(oldMappedMethod.getName())) {484 oldMappedMethod = null;485 }486 if (!resolvedMethodName.equals(handlerMethod.getName())) {487 if (oldMappedMethod != null) {488 targetHandlerMethods.put(mappingInfo, oldMappedMethod);489 oldMappedMethod = null;490 } else{491 targetHandlerMethods.remove(mappingInfo);492 }493 }494 }495 }496 if (oldMappedMethod != null) {497 throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '"

498 + lookupPath + "': {" + oldMappedMethod + ", " +handlerMethod499 + "}. If you intend to handle the same path in multiple methods, then factor "

500 + "them out into a dedicated handler class with that path mapped at the type level!");501 }502 }503 }504 }505 if (!targetHandlerMethods.isEmpty()) {506 List matches = new ArrayList(507 targetHandlerMethods.keySet());508 RequestSpecificMappingInfoComparator requestMappingInfoComparator = newRequestSpecificMappingInfoComparator(509 pathComparator, request);510 Collections.sort(matches, requestMappingInfoComparator);511 RequestSpecificMappingInfo bestMappingMatch = matches.get(0);512 String bestMatchedPath =bestMappingMatch.bestMatchedPattern();513 if (bestMatchedPath != null) {514 extractHandlerMethodUriTemplates(bestMatchedPath, lookupPath, request);515 }516 returntargetHandlerMethods.get(bestMappingMatch);517 } else{518 if (!allowedMethods.isEmpty()) {519 throw newHttpRequestMethodNotSupportedException(request.getMethod(),520 StringUtils.toStringArray(allowedMethods));521 }522 throw neworg.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException(523 lookupPath, request.getMethod(), request.getParameterMap());524 }525 }526

527 private booleanuseTypeLevelMapping(HttpServletRequest request) {528 if (!hasTypeLevelMapping() ||ObjectUtils.isEmpty(getTypeLevelMapping().value())) {529 return false;530 }531 Object value =request.getAttribute(HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING);532 return (value != null) ?(Boolean) value : Boolean.TRUE;533 }534

535 final String USE_DEFAULT_SUFFIX_PATTERN = DefaultAnnotationHandlerMapping.class.getName()536 + ".useDefaultSuffixPattern";537

538 private booleanuseSuffixPattern(HttpServletRequest request) {539 Object value =request.getAttribute(USE_DEFAULT_SUFFIX_PATTERN);540 return (value != null) ?(Boolean) value : Boolean.TRUE;541 }542

543 /**

544 * Determines the combined pattern for the given methodLevelPattern and545 * path.546 *

547 * Uses the following algorithm:548 *

  1. 549 *
  2. If there is a type-level mapping with path information, it is550 * {@linkplainPathMatcher#combine(String, String) combined} with the551 * method-level pattern.552 *
  3. If there is a553 * {@linkplainHandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best554 * matching pattern} in the request, it is combined with the555 * method-level pattern.556 *
  4. Otherwise, the method-level pattern is returned.557 *
558 */

559 privateString getCombinedPattern(String methodLevelPattern, String lookupPath, HttpServletRequest request) {560 boolean useSuffixPattern =useSuffixPattern(request);561 if(useTypeLevelMapping(request)) {562 String[] typeLevelPatterns =getTypeLevelMapping().value();563 for(String typeLevelPattern : typeLevelPatterns) {564 if (!typeLevelPattern.startsWith("/")) {565 typeLevelPattern = "/" +typeLevelPattern;566 }567 String combinedPattern =pathMatcher.combine(typeLevelPattern, methodLevelPattern);568 String matchingPattern =getMatchingPattern(combinedPattern, lookupPath, useSuffixPattern);569 if (matchingPattern != null) {570 returnmatchingPattern;571 }572 }573 return null;574 }575 String bestMatchingPattern =(String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);576 if (StringUtils.hasText(bestMatchingPattern) && bestMatchingPattern.endsWith("*")) {577 String combinedPattern =pathMatcher.combine(bestMatchingPattern, methodLevelPattern);578 String matchingPattern =getMatchingPattern(combinedPattern, lookupPath, useSuffixPattern);579 if (matchingPattern != null && !matchingPattern.equals(bestMatchingPattern)) {580 returnmatchingPattern;581 }582 }583 returngetMatchingPattern(methodLevelPattern, lookupPath, useSuffixPattern);584 }585

586 private String getMatchingPattern(String pattern, String lookupPath, booleanuseSuffixPattern) {587 if(pattern.equals(lookupPath)) {588 returnpattern;589 }590 boolean hasSuffix = pattern.indexOf('.') != -1;591 if (useSuffixPattern && !hasSuffix) {592 String patternWithSuffix = pattern + ".*";593 if(pathMatcher.match(patternWithSuffix, lookupPath)) {594 returnpatternWithSuffix;595 }596 }597 if(pathMatcher.match(pattern, lookupPath)) {598 returnpattern;599 }600 boolean endsWithSlash = pattern.endsWith("/");601 if (useSuffixPattern && !endsWithSlash) {602 String patternWithSlash = pattern + "/";603 if(pathMatcher.match(patternWithSlash, lookupPath)) {604 returnpatternWithSlash;605 }606 }607 return null;608 }609

610 @SuppressWarnings("unchecked")611 private voidextractHandlerMethodUriTemplates(String mappedPattern, String lookupPath,612 HttpServletRequest request) {613 Map variables = (Map) request614 .getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);615 int patternVariableCount = StringUtils.countOccurrencesOf(mappedPattern, "{");616 if ((variables == null || patternVariableCount !=variables.size())617 &&pathMatcher.match(mappedPattern, lookupPath)) {618 variables =pathMatcher.extractUriTemplateVariables(mappedPattern, lookupPath);619 Map decodedVariables =urlPathHelper.decodePathVariables(request, variables);620 request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, decodedVariables);621 }622 }623 }624

625 /**

626 * Build a HandlerMethodResolver for the given handler type.627 */

628 privateServletHandlerMethodResolver getMethodResolver(Object handler) {629 Class> handlerClass =ClassUtils.getUserClass(handler);630 ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass);631 if (resolver == null) {632 synchronized (this.methodResolverCache) {633 resolver = this.methodResolverCache.get(handlerClass);634 if (resolver == null) {635 resolver = newServletHandlerMethodResolver(handlerClass);636 this.methodResolverCache.put(handlerClass, resolver);637 }638 }639 }640 returnresolver;641 }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值