springSecurity过滤器之AnonymousAuthenticationFilter

发布时间 2023-05-01 20:31:11作者: shigp1

SpringSecurity提供了匿名登录功能,让我们不登录也能访问。比如/anoy路径及子路径都能匿名访问,配置如下:

@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/anoy/*").anonymous()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .permitAll()
                .and()
                .sessionManagement()
                .sessionFixation()
                .newSession()
                .maximumSessions(1);
    }
}

同时增加controller:

@RestController
@RequestMapping("/anoy")
public class AnoyController {

    @RequestMapping("/foo")
    public String foo(Authentication authentication) {
        return "foo:" + authentication;
    }
}

访问http://localhost:8080/anoy/foo,看到foo:null。可知不需要登录也能访问。将foo方法改成:

 @RequestMapping("/foo")
public String foo() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    return "foo:" + authentication;
}

访问http://localhost:8080/anoy/foo,看到foo:AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]。从上面可知SecurityContextHolder.getContext().getAuthentication()和通过参数注入的Authentication是不相同的。

源码分析

AnonymousAuthenticationFilter

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
		throws IOException, ServletException {
	if (SecurityContextHolder.getContext().getAuthentication() == null) {
		Authentication authentication = createAuthentication((HttpServletRequest) req);
		SecurityContext context = SecurityContextHolder.createEmptyContext();
		context.setAuthentication(authentication);
		SecurityContextHolder.setContext(context);
		if (this.logger.isTraceEnabled()) {
			this.logger.trace(LogMessage.of(() -> "Set SecurityContextHolder to "
					+ SecurityContextHolder.getContext().getAuthentication()));
		}
		else {
			this.logger.debug("Set SecurityContextHolder to anonymous SecurityContext");
		}
	}
	else {
		if (this.logger.isTraceEnabled()) {
			this.logger.trace(LogMessage.of(() -> "Did not set SecurityContextHolder since already authenticated "
					+ SecurityContextHolder.getContext().getAuthentication()));
		}
	}
	chain.doFilter(req, res);
}

判断SecurityContextHolder.getContext().getAuthentication()是否为空,如果不为空则是认证登录。否则设置匿名用户和角色。并将匿名用户设置到SecurityContextHolder中。

	protected Authentication createAuthentication(HttpServletRequest request) {
	AnonymousAuthenticationToken token = new AnonymousAuthenticationToken(this.key, this.principal,
			this.authorities);
	token.setDetails(this.authenticationDetailsSource.buildDetails(request));
	return token;
}

createAuthentication创建用户名为anonymousUser,角色为ROLE_ANONYMOUS的匿名用户。