【参考文章】: Spring Security 认证流程 (写的很形象)
认证功能由 springSecurityFilterChain 中的 UsernamePasswordAuthenticationFilter 实现
该类下有三个子类,子类都没有重写doFilter(),都是调用父类的doFilter()
doFilter()中调用了子类的attemptAuthentication()进行真正的认证逻辑处理
public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; if (!requiresAuthentication(request, response)) { chain.doFilter(request, response); return; } Authentication authResult; try { // 调用子类实现的抽象方法,返回一个验证对象 // 该方法的实现才是真正处理验证逻辑 authResult = attemptAuthentication(request, response); if (authResult == null) { return; } sessionStrategy.onAuthentication(authResult, request, response); } catch (InternalAuthenticationServiceException failed) { // 验证失败 logger.error("An internal error occurred while trying to authenticate the user.",failed); unsuccessfulAuthentication(request, response, failed); return; } catch (AuthenticationException failed) { // 验证失败 unsuccessfulAuthentication(request, response, failed); return; } // 验证成功 if (continueChainBeforeSuccessfulAuthentication) { chain.doFilter(request, response); } successfulAuthentication(request, response, chain, authResult); } }
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter { // 默认处理POST方法的 /login请求(这是默认的登录请求URI) public UsernamePasswordAuthenticationFilter() { super(new AntPathRequestMatcher("/login", "POST")); } public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { // 只处理POST方法的请求 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(); // 后续AuthenticationProvider 会根据 authRequest 的 class 类型判断自己是否进行认证 UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken( username, password); setDetails(request, authRequest); // 此处 his.getAuthenticationManager() 返回的是 ProviderManager return this.getAuthenticationManager().authenticate(authRequest); } }
管理负责认证的 AuthenticationProvider
默认的 providers 只有一个,类型为 AnonymousAuthenticationProvider
默认的 parent 类型为 ProviderManager , 其 providers 为 DaoAuthenticationProvider, 默认情况下最终由 DaoAuthenticationProvider 处理认证
public class ProviderManager implements AuthenticationManager, MessageSourceAware,InitializingBean { public Authentication authenticate(Authentication authentication)throws AuthenticationException { for (AuthenticationProvider provider : getProviders()) { // 不支持认证, 则跳过 if (!provider.supports(toTest)) { continue; } try { result = provider.authenticate(authentication); if (result != null) { copyDetails(authentication, result); // 有一个 AuthenticationProvider 认证通过则结束 break; } } catch (AccountStatusException | InternalAuthenticationServiceException e) { prepareException(e, authentication); throw e; } catch (AuthenticationException e) { lastException = e; } } if (result == null && parent != null) { try { // 所有的provider都不支持校验, 则由parent进行校验 result = parentResult = parent.authenticate(authentication); } catch (ProviderNotFoundException e) { } catch (AuthenticationException e) { lastException = parentException = e; } } if (result != null) { if (eraseCredentialsAfterAuthentication&& (result instanceof CredentialsContainer)) { ((CredentialsContainer) result).eraseCredentials(); } if (parentResult == null) { eventPublisher.publishAuthenticationSuccess(result); } return result; } ...省略其他代码 } }
处理认证默认配置