authorizationfilter过滤器的作用
在 spring security 框架中,authorizationfilter 是负责执行授权(authorization) 决策的核心过滤器。根据当前的 authentication(认证信息)和请求上下文,判断当前用户是否有权限访问目标资源。
先看段源码
public class authorizationfilter extends genericfilterbean {
...
private final authorizationmanager<httpservletrequest> authorizationmanager;
/**
* creates an instance.
* @param authorizationmanager the {@link authorizationmanager} to use
*/
public authorizationfilter(authorizationmanager<httpservletrequest> authorizationmanager) {
assert.notnull(authorizationmanager, "authorizationmanager cannot be null");
this.authorizationmanager = authorizationmanager;
}
@override
public void dofilter(servletrequest servletrequest, servletresponse servletresponse, filterchain chain)
throws servletexception, ioexception {
httpservletrequest request = (httpservletrequest) servletrequest;
httpservletresponse response = (httpservletresponse) servletresponse;
if (this.observeonceperrequest && isapplied(request)) {
chain.dofilter(request, response);
return;
}
if (skipdispatch(request)) {
chain.dofilter(request, response);
return;
}
string alreadyfilteredattributename = getalreadyfilteredattributename();
request.setattribute(alreadyfilteredattributename, boolean.true);
try {
//授权决策
authorizationdecision decision = this.authorizationmanager.check(this::getauthentication, request);
this.eventpublisher.publishauthorizationevent(this::getauthentication, request, decision);
if (decision != null && !decision.isgranted()) {
throw new accessdeniedexception("access denied");
}
chain.dofilter(request, response);
}
finally {
request.removeattribute(alreadyfilteredattributename);
}
}
从上面的代码中可以看出:authorizationfilter 本身不直接做授权判断,而是委托给一个 authorizationmanager 接口.
authorizationmanager
从上面的代码中可以看出,授权的核心在于调用authorizationmanager的check方法,去决定当前的authentication是否有权限访问request
//授权决策 authorizationdecision decision = this.authorizationmanager.check(this::getauthentication, request);
@functionalinterface
public interface authorizationmanager<t> {
/**
* determines if access should be granted for a specific authentication and object.
* @param authentication the {@link supplier} of the {@link authentication} to check
* @param object the {@link t} object to check
* @throws accessdeniedexception if access is not granted
*/
default void verify(supplier<authentication> authentication, t object) {
authorizationdecision decision = check(authentication, object);
if (decision != null && !decision.isgranted()) {
throw new accessdeniedexception("access denied");
}
}
/**
* determines if access is granted for a specific authentication and object.
* @param authentication the {@link supplier} of the {@link authentication} to check
* @param object the {@link t} object to check
* @return an {@link authorizationdecision} or null if no decision could be made
*/
@nullable
authorizationdecision check(supplier<authentication> authentication, t object);
}
authorizationmanager接口定义了check方法,为什么说叫授权决策,因为check方法返回的是authorizationdecision,这是一种授权结果 里面有个字段granted,用来决定是否有权限继续访问当前资源。
public class authorizationdecision implements authorizationresult {
private final boolean granted;
public authorizationdecision(boolean granted) {
this.granted = granted;
}
@override
public boolean isgranted() {
return this.granted;
}
@override
public string tostring() {
return getclass().getsimplename() + " [granted=" + this.granted + "]";
}
}
requestmatcherdelegatingauthorizationmanager
如果你去调试你会发现authorizationfilter委托的authorizationmanager的实现类是 requestmatcherdelegatingauthorizationmanager,至于为什么是这个实现类,我们后续会出一个文章专门来讲解,大体还是httpsecurity,因为它就是用来配置过滤器链的,底层就是配置过滤器的。这里不会多讲。拆解一下这个类的名字
- requestmatcher:请求匹配器,用于匹配不同的 http 请求(如 /admin/**, /public/**)
- delegating:代表“委派”,即它自己不做判断,而是把任务委派给其他具体的 authorizationmanager
- authorizationmanager:授权管理接口,负责做出“允许”或“拒绝”的决策
requestmatcherdelegatingauthorizationmanager 内部维护了一个列表mappings:
public final class requestmatcherdelegatingauthorizationmanager implements authorizationmanager<httpservletrequest> {
private static final authorizationdecision deny = new authorizationdecision(false);
private final list<requestmatcherentry<authorizationmanager<requestauthorizationcontext>>> mappings;
/**
* a rich object for associating a {@link requestmatcher} to another object.
* 从注释中可以看出requestmatcherentry就是用来将requestmatcher和其他对象建立关联的
* @author marcus da coregio
* @since 5.5.5
*/
public class requestmatcherentry<t> {
private final requestmatcher requestmatcher;
private final t entry;
public requestmatcherentry(requestmatcher requestmatcher, t entry) {
this.requestmatcher = requestmatcher;
this.entry = entry;
}
public requestmatcher getrequestmatcher() {
return this.requestmatcher;
}
public t getentry() {
return this.entry;
}
}
mappings中的每个条目requestmatcherentry代表着一种映射关系,里面包含了
- 一个 requestmatcher(比如 antpathrequestmatcher("/admin/**", "get"))
- 一个对应的 authorizationmanager(比如负责判断 hasrole('admin') 的管理器)
接下来我们看下requestmatcherdelegatingauthorizationmanager的check流程
/**
* delegates to a specific {@link authorizationmanager} based on a
* {@link requestmatcher} evaluation.
* @param authentication the {@link supplier} of the {@link authentication} to check
* @param request the {@link httpservletrequest} to check
* @return an {@link authorizationdecision}. if there is no {@link requestmatcher}
* matching the request, or the {@link authorizationmanager} could not decide, then
* null is returned
*/
@override
public authorizationdecision check(supplier<authentication> authentication, httpservletrequest request) {
if (this.logger.istraceenabled()) {
this.logger.trace(logmessage.format("authorizing %s", requestline(request)));
}
for (requestmatcherentry<authorizationmanager<requestauthorizationcontext>> mapping : this.mappings) {
requestmatcher matcher = mapping.getrequestmatcher();
matchresult matchresult = matcher.matcher(request);
if (matchresult.ismatch()) {
authorizationmanager<requestauthorizationcontext> manager = mapping.getentry();
if (this.logger.istraceenabled()) {
this.logger.trace(
logmessage.format("checking authorization on %s using %s", requestline(request), manager));
}
return manager.check(authentication,
new requestauthorizationcontext(request, matchresult.getvariables()));
}
}
if (this.logger.istraceenabled()) {
this.logger.trace(logmessage.of(() -> "denying request since did not find matching requestmatcher"));
}
return deny;
}
从上面的代码我们可以看出check的核心流程是:当请求到来时,它会:
- 遍历这个列表,取出里面的每个requestmatcher,然后去判断当前
requestmatcher是否和当前请求request匹配,找到匹配后,找到和requestmatcher匹配的authorizationmanager - 将授权任务委托给该条目对应的
authorizationmanager。 - 如果没有任何匹配,默认拒绝(或使用默认策略)。
mappings列表中注册的requestmatcher和authorizationmanager关系是如何绑定的
后续我会专门出一期文章从源码角度讲解requestmatcherdelegatingauthorizationmanager是如何完成创建以及初始化mappings的,这里我们会如何使用就好啦。我们经常在配置过滤器链的时候有如下配置
@bean
public securityfilterchain defaultsecurityfilterchain(httpsecurity http)
throws exception {
system.out.println("filterchain http: " + system.identityhashcode(http));
http
.authorizehttprequests((authorize) -> authorize
.requestmatchers("/admin/**").hasrole("admin")
.anyrequest().authenticated()
);
return http.build();
}
比如这句代码.requestmatchers("/admin/**").hasrole("admin")就是在配置mappings映射关系,也就是当访问/admin/**时,底层会创建一个authorityauthorizationmanager来处理授权决策(这块后面出一篇文章细讲),.hasrole("admin")底层会创建一个authorizationmanager来处理授权请求。
授权结果
从 authorizationfilter的源码中我们知道,如果授权没通过的话就会抛出一个accessdeniedexception异常,这个异常通常会被exceptiontranslationfilter过滤器捕获 然后进行处理,这个我们后续再将
if (decision != null && !decision.isgranted()) { throw new accessdeniedexception("access denied"); }
总结
authorizationfilter过滤器是用来实现授权决策的,但是它会委托给 requestmatcherdelegatingauthorizationmanager来实现具体的授权决策,结合当前请求和authentication来决定是否有权限。但是这里我也留下了几处坑,没有填,后续我会写文章继续填坑
- authorizationfilter里面的requestmatcherdelegatingauthorizationmanager是什么时候配置的
- requestmatcherdelegatingauthorizationmanager需要维护一个mappings,用来映射requestmatcher和authorizationmanager
- 用户配置调用的
requestmatchers("/admin/**").hasrole("admin")等配置,最后怎么生效的,底层原理是什么 4.授权没通过抛出的异常被 exceptiontranslationfilter捕获后如何自定义处理。
到此这篇关于java中authorizationfilter过滤器的功能的文章就介绍到这了,更多相关java authorizationfilter过滤器内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论