在Spring Security中,通过设置entry-point-ref="第三方登录入口",可以在访问系统首页的时候进行登录跳转。如
<http pattern="/**" entry-point-ref="casEntryPoint">
.....
</http>
它在系统进行登录认证的过程会进行认证,认证不通过则抛出一个异常给ExceptionTranslationFilter,由它进行通过entry-point-ref设置的入口点进行处理。
所以按照SpringSecurity的过滤器的顺序可判断,其异常是由FilterSecurityInterceptor抛出的。经过层层推进,我们在其抽象类AbstractSecurityInterceptor中的beforeInvocation方法中找到了抛出异常的地方,其调用了authenticateIfRequired方法,方法如下
private Authentication authenticateIfRequired() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication.isAuthenticated() && !alwaysReauthenticate) {
if (logger.isDebugEnabled()) {
logger.debug("Previously Authenticated: " + authentication);
}
return authentication;
}
authentication = authenticationManager.authenticate(authentication);
// We don't authenticated.setAuthentication(true), because each provider should do that
if (logger.isDebugEnabled()) {
logger.debug("Successfully Authenticated: " + authentication);
}
SecurityContextHolder.getContext().setAuthentication(authentication);
return authentication;
}
但是,让人很奇怪的是SecurityContext中的authentication是从哪来的,我们还没有登录呀。不要着急,让我们接下来一探究竟。
我们知道,在SpringSecurity的过滤链中存在一个匿名登录的过滤器,AnonymousAuthenticationFilter,你可以添加anonymous元素进行设置,但是默认可以不加。而默认后会对AnonymousAuthenticationFilter的一些属性进行设置,并将其返回到过滤链中,所以这个请求是要经过匿名过滤器的。所以让我们来看一下它的doFilter方法
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
if (applyAnonymousForThisRequest((HttpServletRequest) req)) {
if (SecurityContextHolder.getContext().getAuthentication() == null) {
//这就是设置authentication的地方
SecurityContextHolder.getContext().setAuthentication(createAuthentication((HttpServletRequest) req));
if (logger.isDebugEnabled()) {
logger.debug("Populated SecurityContextHolder with anonymous token: '"
+ SecurityContextHolder.getContext().getAuthentication() + "'");
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("SecurityContextHolder not populated with anonymous token, as it already contained: '"
+ SecurityContextHolder.getContext().getAuthentication() + "'");
}
}
}
chain.doFilter(req, res);
}
可以看出,我们确实对SecurityContext设置了authentication,所以在之后的FilterSecurityInterceptor中才会得到,之后才会有对authentication的认证。如何认证的就不加以描述了。