spring security4.x 入门流程源码讲解
1.AbstractAuthenticationProcessingFilter 抽象的authencationProcessingFilter 用于过滤验证是否需要拦截以及认证
(1).首先查看doFilter方法
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;
}
if (logger.isDebugEnabled()) {
logger.debug("Request is to process authentication");
}
Authentication authResult;
try {
//预身份验证,由子类 UsernamePasswordAuthenticationFilter 实现执行
authResult = attemptAuthentication(request, response);
if (authResult == null) {
// return immediately as subclass has indicated that it hasn't completed
// authentication
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) {
// Authentication failed
unsuccessfulAuthentication(request, response, failed);
return;
}
// Authentication success
if (continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
successfulAuthentication(request, response, chain, authResult);
}
2.1UsernamePasswordAuthenticationFilter 他是AbstractAuthenticationProcessingFilter过滤器的实现。但是他还不是执行验证逻辑的过滤器!
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();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
//此时真实的验证由AuthenticationProvider的实现AbstractUserDetailsAuthenticationProvider的 authenticate(Authentication authentication)方法执行验证逻辑 AuthenticationProvider会有很多不同provider,可以自定义实现自己的provider 例如除了帐号和密码验证之外还有验证码,此时就需要继承AuthenticationProvider实现自定义provider。
return this.getAuthenticationManager().authenticate(authRequest);
}
2.2验证失败调用AbstractAuthenticationProcessingFilter 的unsuccessfulAuthentication(HttpServletRequest request,HttpServletResponse response, AuthenticationException failed) 方法 失败可以自定义failureHandler 用于自定义返回值
protected void unsuccessfulAuthentication(HttpServletRequest request,
HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
SecurityContextHolder.clearContext();
if (logger.isDebugEnabled()) {
logger.debug("Authentication request failed: " + failed.toString(), failed);
logger.debug("Updated SecurityContextHolder to contain null Authentication");
logger.debug("Delegating to authentication failure handler " + failureHandler);
}
rememberMeServices.loginFail(request, response);
failureHandler.onAuthenticationFailure(request, response, failed);
}
2.3验证成功调用AbstractAuthenticationProcessingFilter 的successfulAuthentication(HttpServletRequest request,HttpServletResponse response, FilterChain chain, Authentication authResult) 方法 ,认证成功主要内容为:把认证信息存入SecurityContextHolder;通知认证成功给用户。同样我们可以自定义successHandler,返回JSON返回XML,
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response, FilterChain chain, Authentication authResult)
throws IOException, ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Authentication success. Updating SecurityContextHolder to contain: "
+ authResult);
}
SecurityContextHolder.getContext().setAuthentication(authResult);
rememberMeServices.loginSuccess(request, response, authResult);
// Fire event
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
authResult, this.getClass()));
}
successHandler.onAuthenticationSuccess(request, response, authResult);
}
注意: 到这里整改认证过程就执行完了,后续会补入一个流程图,让大家看的更清晰,下次再讲授权关于授权流程。
可以关注下博主的公众号,实时推送解决方案!