问题场景:
登录成功后,在执行某个功能操作(例如:系统管理模块的删除功能时),会去执行UserDetailsService.loadUserByUsername 再次进行用户认证。
出现问题版本 Spring security 4.04 、 4.10
通过源码分析发现BasicAuthenticationFilter.authenticationIsRequired(username) 一直返回true (true表示需要认证)
org.springframework.security.web.authentication.www.BasicAuthenticationFilter.class
关键代码分析
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { ... try { ... if (<span style="color:#ff0000;"><strong>authenticationIsRequired(username)</strong></span>) { UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, tokens[1]); authRequest.setDetails( this.authenticationDetailsSource.buildDetails(request)); Authentication authResult = this.authenticationManager .authenticate(authRequest); if (debug) { this.logger.debug("Authentication success: " + authResult); } SecurityContextHolder.getContext().setAuthentication(authResult); this.rememberMeServices.loginSuccess(request, response, authResult); onSuccessfulAuthentication(request, response, authResult); } } catch (AuthenticationException failed) { ... } chain.doFilter(request, response); }
private boolean authenticationIsRequired(String username) { // Only reauthenticate if username doesn't match SecurityContextHolder and user // isn't authenticated // (see SEC-53) Authentication existingAuth = SecurityContextHolder.getContext() .getAuthentication(); if (existingAuth == null || !existingAuth.isAuthenticated()) { return true; } // Limit username comparison to providers which use usernames (ie // UsernamePasswordAuthenticationToken) // (see SEC-348) if (existingAuth instanceof UsernamePasswordAuthenticationToken && !<strong><span style="color:#ff0000;">existingAuth.getName().equals(username)</span></strong>) { return true; } // Handle unusual condition where an AnonymousAuthenticationToken is already // present // This shouldn't happen very often, as BasicProcessingFitler is meant to be // earlier in the filter // chain than AnonymousAuthenticationFilter. Nevertheless, presence of both an // AnonymousAuthenticationToken // together with a BASIC authentication request header should indicate // reauthentication using the // BASIC protocol is desirable. This behaviour is also consistent with that // provided by form and digest, // both of which force re-authentication if the respective header is detected (and // in doing so replace // any existing AnonymousAuthenticationToken). See SEC-610. if (existingAuth instanceof AnonymousAuthenticationToken) { return true; } return false; }