Spring Security之核心安全过滤器

张开发
2026/6/17 6:16:11 15 分钟阅读
Spring Security之核心安全过滤器
Spring Security的核心安全过滤器是其实现认证和授权等安全功能的关键组件。下面以UsernamePasswordAuthenticationFilter和FilterSecurityInterceptor这两个重要的过滤器为例进行源码分析。UsernamePasswordAuthenticationFilterUsernamePasswordAuthenticationFilter主要用于处理基于表单的用户名和密码登录认证。继承结构publicclassUsernamePasswordAuthenticationFilterextendsAbstractAuthenticationProcessingFilter它继承自AbstractAuthenticationProcessingFilter该类提供了认证处理的通用逻辑。关键方法attemptAuthentication方法publicAuthenticationattemptAuthentication(HttpServletRequestrequest,HttpServletResponseresponse)throwsAuthenticationException{if(postOnly!request.getMethod().equals(POST)){thrownewAuthenticationServiceException(Authentication method not supported: request.getMethod());}StringusernameobtainUsername(request);StringpasswordobtainPassword(request);if(usernamenull){username;}if(passwordnull){password;}usernameusername.trim();UsernamePasswordAuthenticationTokenauthRequestnewUsernamePasswordAuthenticationToken(username,password);// Allow subclasses to set the details propertysetDetails(request,authRequest);returnthis.getAuthenticationManager().authenticate(authRequest);}- 首先检查请求方法是否为POST如果不是且配置为仅支持POST方法则抛出异常。 - 通过obtainUsername和obtainPassword方法从请求中获取用户名和密码。 - 创建一个UsernamePasswordAuthenticationToken此时该Token处于未认证状态isAuthenticated为false。 - 调用setDetails方法设置Authentication对象的细节信息如客户端IP等。 - 最后通过AuthenticationManager进行认证AuthenticationManager会调用注册的AuthenticationProvider来验证用户凭据。obtainUsername和obtainPassword方法protectedStringobtainUsername(HttpServletRequestrequest){returnrequest.getParameter(usernameParameter);}protectedStringobtainPassword(HttpServletRequestrequest){returnrequest.getParameter(passwordParameter);}默认从请求参数中获取用户名和密码参数名分别为username和password可以通过setUsernameParameter和setPasswordParameter方法进行修改。FilterSecurityInterceptorFilterSecurityInterceptor负责对进入应用的请求进行授权检查。继承结构publicfinalclassFilterSecurityInterceptorextendsAbstractSecurityInterceptorimplementsFilter它继承自AbstractSecurityInterceptor并实现了Filter接口。关键方法doFilter方法publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{HttpServletRequesthttpRequest(HttpServletRequest)request;HttpServletResponsehttpResponse(HttpServletResponse)response;FilterInvocationfinewFilterInvocation(request,response,chain);invoke(fi);}创建一个FilterInvocation对象该对象包含了请求、响应和过滤器链等信息然后调用invoke方法进行授权处理。invoke方法privatevoidinvoke(FilterInvocationfi)throwsIOException,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);}// 获取当前请求的配置属性ListConfigAttributeattributesthis.obtainSecurityMetadataSource().getAttributes(fi);if(attributesnull||attributes.isEmpty()){fi.getChain().doFilter(fi.getRequest(),fi.getResponse());}else{// 获取当前认证的用户Authenticationauthenticatedthis.authenticationManager.authenticate(newPreInvocationAuthorizationToken(null,fi,attributes));try{// 进行授权检查this.accessDecisionManager.decide(authenticated,fi,attributes);}catch(AccessDeniedExceptionaccessDeniedException){// 授权失败处理publishEvent(newAuthorizationFailureEvent(fi,attributes,authenticated,accessDeniedException));throwaccessDeniedException;}// 授权成功放行请求this.finallyInvocationChecker.beforeInvocation(fi);try{fi.getChain().doFilter(fi.getRequest(),fi.getResponse());}finally{this.finallyInvocationChecker.afterInvocation(fi,null);}}}}- 首先检查该请求是否已经被处理过如果是则直接通过过滤器链放行请求。 - 通过obtainSecurityMetadataSource获取当前请求的配置属性这些属性定义了访问该请求所需的权限等信息。 - 如果没有配置属性则直接放行请求。 - 使用AuthenticationManager对一个PreInvocationAuthorizationToken进行认证该Token包含了请求相关信息。 - 通过accessDecisionManager进行授权决策如果授权失败则抛出AccessDeniedException并发布授权失败事件。 - 如果授权成功则通过过滤器链继续处理请求。

更多文章