spring security 认证与授权下篇

上篇回顾

匿名用户经过  匿名访问过滤器 将会在contextHolder中存储一个匿名认证,经过异常处理拦截器,经过权限校验拦截器,由于是匿名认证所以权限管理器通过投票器校验失败,抛出权限校验异常,异常处理拦截器处理调用认证切入点重定向到/login 路径下,如果您已经理解了就可以在继续往下看了。如果没有还请您进行断点调试
 

匿名访问经过的第四个待分析的拦截器DefaultLoginPageGeneratingFilter

 

这个过滤器的实现就比较简单,就是判断当前路径是不是/login  如果是,就调用 response 输出一个登陆页面

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		boolean loginError = isErrorPage(request);
		boolean logoutSuccess = isLogoutSuccess(request);
        //如果是/login /login?error 或是登出的话返回登录页面
		if (isLoginUrlRequest(request) || loginError || logoutSuccess) {
			String loginPageHtml = generateLoginPageHtml(request, loginError,
					logoutSuccess);
			response.setContentType("text/html;charset=UTF-8");
			response.setContentLength(loginPageHtml.getBytes(StandardCharsets.UTF_8).length);
			response.getWriter().write(loginPageHtml);

			return;
		}

		chain.doFilter(request, response);
	}

这样就返回了登录页面

匿名访问经过的第四个待分析的拦截器UsernamePasswordAuthenticationFilter

当提交登录后就到这个过滤器进行处理,该过滤器捕获/login method 为 post ,大致流程为调用 AuthenticationManager的provider进行认证,provider调用userDetailsService进行用户数据的读取返回给provider ,provider 将密码使用编码器进行编码后校验如果成功就返回认证过得,失败抛异常,AuthenticationManager的默认实现类为ProviderManager,provider的默认实现类为DaoAuthenticationProvider,UserDetailsService可以简单看一下JdbcDaoImpl,实现过程较简单,读者可以自行阅读

public Authentication attemptAuthentication(HttpServletRequest request,
			HttpServletResponse response) throws AuthenticationException {
		

		String username = obtainUsername(request);
		String password = obtainPassword(request);
		UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
				username, password);

		setDetails(request, authRequest);
//调用 AuthenticationManager的provider进行认证,provider调用userDetailsService进行用户数据的读取返回给provider ,provider 将密码使用编码器进行编码后校验如果成功就返回认证过得,失败抛异常
		return this.getAuthenticationManager().authenticate(authRequest);
	}

此处是一个模板设计模式,父类完成核心逻辑的实现,将认证过程交给子类实现,父类核心代码分析:

public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean
		implements ApplicationEventPublisherAware, MessageSourceAware {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		
		Authentication authResult;
		try {
            //模板设计模式,交给子类实现
			authResult = attemptAuthentication(request, response);
			if (authResult == null) {
				return;
			}

		    //session固话攻击和并发控制策略
			sessionStrategy.onAuthentication(authResult, request, response);
		}
		catch (InternalAuthenticationServiceException failed) {
			//认证失败
			unsuccessfulAuthentication(request, response, failed);

			return;
		}
		catch (AuthenticationException failed) {
			
			unsuccessfulAuthentication(request, response, failed);

			return;
		}

		// Authentication success
		if (continueChainBeforeSuccessfulAuthentication) {
			chain.doFilter(request, response);
		}
        //认证成功
		successfulAuthentication(request, response, chain, authResult);
	}
}

此处有两点需要查看就是认证成功做了什么,认证失败又做了什么?

protected void successfulAuthentication(HttpServletRequest request,
			HttpServletResponse response, FilterChain chain, Authentication authResult)
			throws IOException, ServletException {
        //将认证放入context中
		SecurityContextHolder.getContext().setAuthentication(authResult);
        //记住我
		rememberMeServices.loginSuccess(request, response, authResult);
        //成功处理器,默认为SavedRequestAwareAuthenticationSuccessHandler
		successHandler.onAuthenticationSuccess(request, response, authResult);
	}



//
//SavedRequestAwareAuthenticationSuccessHandler核心逻辑
@Override
	public void onAuthenticationSuccess(HttpServletRequest request,
			HttpServletResponse response, Authentication authentication)
			throws ServletException, IOException {
        //这在异常处理过滤器中将请求的路径存了进行,以实现源路径的跳转
		SavedRequest savedRequest = requestCache.getRequest(request, response);
		getRedirectStrategy().sendRedirect(request, response, targetUrl);
	}

失败做了什么呢?

失败简单的调用了 rememberMeServices.loginfailes()

认证访问经过的拦截器LogoutFilter

 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;
        if (this.requiresLogout(request, response)) {
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
             //核心代码,有一系列的handler 比如CsrfLogoutHandler 
             //SecurityContextLogoutHandler
             //及记住我的service等,这也体现了架构的整体性与灵活性
            this.handler.logout(request, response, auth);
            this.logoutSuccessHandler.onLogoutSuccess(request, response, auth);
        } else {
            chain.doFilter(request, response);
        }
    }

总结

好了,到此为止认证与授权的全部全部内容就完结了,剩下 记住我,session 固话攻击和并发讲完,spring security就彻底完结了

现在总结一下组件:

  • SecurityContextHolder
  • SecurityContext
  • Authentication
  • GrantedAuthority
  • UserDetails
  • AuthenticationManager
  • ProviderManager 
  • AuthenticationProvider 
  • UserDetailsService
  • AccessDecisionManager
  • 投票器
  • 认证切入点等

  • 下面介绍一下默认的全部拦截器:
  • ChannelProcessingFilter
  • SecurityContextPersistenceFilter
  • ConcurrentSessionFilter
  • Authentication processing mechanisms - UsernamePasswordAuthenticationFilterCasAuthenticationFilterBasicAuthenticationFilter 
  • SecurityContextHolderAwareRequestFilter
  • RememberMeAuthenticationFilter
  • AnonymousAuthenticationFilter
  • ExceptionTranslationFilter
  • FilterSecurityInterceptor

你可能感兴趣的:(spring,security)