spring security权限路由匹配restful格式的详情id设计

解决方案:

先直接说下解决方案,权限点设计成如下:

/api/books/{id:\d*}

问题描述:

获取书本详情的标准restful路由,一般是这样的/api/books/12, 12即该book的id,如果需要拥有访问该路由的权限,一般可以这样设计/api/books/*

但是如果类似有一个获取书本封面的请求,比如:/api/books/getCover,那么如果给了/api/books/*这样的权限的话,getCover这个也可以请求成功,就无法区分了。


源码分析:

请求地址和权限点匹配判断代码:

if(antPathMatcher.match(permission.getRequestUrl(),requestUri)){
	...
}

匹配代码的源码如下:
在这里插入图片描述那我们来分析下matchStrings 这个方法

private boolean matchStrings(String pattern, String str,
		@Nullable Map<String, String> uriTemplateVariables) {

	return getStringMatcher(pattern).matchStrings(str, uriTemplateVariables);
}

接下来看下getStringMatcher

protected AntPathStringMatcher getStringMatcher(String pattern) {
	AntPathStringMatcher matcher = null;
	Boolean cachePatterns = this.cachePatterns;
	if (cachePatterns == null || cachePatterns.booleanValue()) {
		matcher = this.stringMatcherCache.get(pattern);
	}
	if (matcher == null) {
		matcher = new AntPathStringMatcher(pattern, this.caseSensitive);
		if (cachePatterns == null && this.stringMatcherCache.size() >= CACHE_TURNOFF_THRESHOLD) {
			// Try to adapt to the runtime situation that we're encountering:
			// There are obviously too many different patterns coming in here...
			// So let's turn off the cache since the patterns are unlikely to be reoccurring.
			deactivatePatternCache();
			return matcher;
		}
		if (cachePatterns == null || cachePatterns.booleanValue()) {
			this.stringMatcherCache.put(pattern, matcher);
		}
	}
	return matcher;
}

接下来看AntPathStringMatcher的构造函数:

public AntPathStringMatcher(String pattern, boolean caseSensitive) {
	this.rawPattern = pattern;
	this.caseSensitive = caseSensitive;
	StringBuilder patternBuilder = new StringBuilder();
	Matcher matcher = GLOB_PATTERN.matcher(pattern);
	int end = 0;
	while (matcher.find()) {
		patternBuilder.append(quote(pattern, end, matcher.start()));
		String match = matcher.group();
		if ("?".equals(match)) {
			patternBuilder.append('.');
		}
		else if ("*".equals(match)) {
			patternBuilder.append(".*");
		}
		else if (match.startsWith("{") && match.endsWith("}")) {
			int colonIdx = match.indexOf(':');
			if (colonIdx == -1) {
				patternBuilder.append(DEFAULT_VARIABLE_PATTERN);
				this.variableNames.add(matcher.group(1));
			}
			else {
				String variablePattern = match.substring(colonIdx + 1, match.length() - 1);
				patternBuilder.append('(');
				patternBuilder.append(variablePattern);
				patternBuilder.append(')');
				String variableName = match.substring(1, colonIdx);
				this.variableNames.add(variableName);
			}
		}
		end = matcher.end();
	}
	// No glob pattern was found, this is an exact String match
	if (end == 0) {
		this.exactMatch = true;
		this.pattern = null;
	}
	else {
		this.exactMatch = false;
		patternBuilder.append(quote(pattern, end, pattern.length()));
		this.pattern = Pattern.compile(patternBuilder.toString(),
				Pattern.DOTALL | (this.caseSensitive ? 0 : Pattern.CASE_INSENSITIVE));
	}
}

看到这里基本上也就明白了,这里如果设定的*号,这匹配的是.*,那参考这里

else if (match.startsWith("{") && match.endsWith("}")) {

我们把获取详情的权限点设计成

/api/books/{id:\d*}

这样就可以匹配/api/books/12或者/api/books/123之类的详情,又不会包含/api/books/getCover这样的接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

F_angT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值