Spring Security之核心安全过滤器
·
Spring Security的核心安全过滤器是其实现认证和授权等安全功能的关键组件。下面以UsernamePasswordAuthenticationFilter和FilterSecurityInterceptor这两个重要的过滤器为例,进行源码分析。
UsernamePasswordAuthenticationFilter
UsernamePasswordAuthenticationFilter主要用于处理基于表单的用户名和密码登录认证。
- 继承结构
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter
它继承自AbstractAuthenticationProcessingFilter,该类提供了认证处理的通用逻辑。
- 关键方法
attemptAuthentication方法
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly &&!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
- 首先检查请求方法是否为`POST`,如果不是且配置为仅支持`POST`方法,则抛出异常。
- 通过`obtainUsername`和`obtainPassword`方法从请求中获取用户名和密码。
- 创建一个`UsernamePasswordAuthenticationToken`,此时该`Token`处于未认证状态(`isAuthenticated`为`false`)。
- 调用`setDetails`方法设置`Authentication`对象的细节信息,如客户端IP等。
- 最后通过`AuthenticationManager`进行认证,`AuthenticationManager`会调用注册的`AuthenticationProvider`来验证用户凭据。
obtainUsername和obtainPassword方法
protected String obtainUsername(HttpServletRequest request) {
return request.getParameter(usernameParameter);
}
protected String obtainPassword(HttpServletRequest request) {
return request.getParameter(passwordParameter);
}
默认从请求参数中获取用户名和密码,参数名分别为username和password,可以通过setUsernameParameter和setPasswordParameter方法进行修改。
FilterSecurityInterceptor
FilterSecurityInterceptor负责对进入应用的请求进行授权检查。
- 继承结构
public final class FilterSecurityInterceptor extends AbstractSecurityInterceptor
implements Filter
它继承自AbstractSecurityInterceptor,并实现了Filter接口。
- 关键方法
doFilter方法
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
创建一个FilterInvocation对象,该对象包含了请求、响应和过滤器链等信息,然后调用invoke方法进行授权处理。
invoke方法
private void invoke(FilterInvocation fi) throws IOException, ServletException {
// 如果已经处理过该请求,直接放行
if (fi.getRequest() != null &&
(fi.getRequest().getAttribute(FILTER_APPLIED) != null || observeOncePerRequest)) {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} else {
// 标记该请求已处理
if (fi.getRequest() != null) {
fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);
}
// 获取当前请求的配置属性
List<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(fi);
if (attributes == null || attributes.isEmpty()) {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} else {
// 获取当前认证的用户
Authentication authenticated = this.authenticationManager.authenticate(
new PreInvocationAuthorizationToken(null, fi, attributes));
try {
// 进行授权检查
this.accessDecisionManager.decide(authenticated, fi, attributes);
} catch (AccessDeniedException accessDeniedException) {
// 授权失败处理
publishEvent(new AuthorizationFailureEvent(fi, attributes, authenticated, accessDeniedException));
throw accessDeniedException;
}
// 授权成功,放行请求
this.finallyInvocationChecker.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
this.finallyInvocationChecker.afterInvocation(fi, null);
}
}
}
}
- 首先检查该请求是否已经被处理过,如果是则直接通过过滤器链放行请求。
- 通过`obtainSecurityMetadataSource`获取当前请求的配置属性,这些属性定义了访问该请求所需的权限等信息。
- 如果没有配置属性,则直接放行请求。
- 使用`AuthenticationManager`对一个`PreInvocationAuthorizationToken`进行认证,该`Token`包含了请求相关信息。
- 通过`accessDecisionManager`进行授权决策,如果授权失败则抛出`AccessDeniedException`并发布授权失败事件。
- 如果授权成功,则通过过滤器链继续处理请求。
更多推荐





所有评论(0)