以前有篇文章講了怎麼進行免登陸動態配置的方案,動用了反射去實現,有點黑魔法的味道,這裏再介紹另一種方案css
spring-security-config-4.2.3.RELEASE-sources.jar!/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.javajava
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>> extends AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> { static final String permitAll = "permitAll"; private static final String denyAll = "denyAll"; private static final String anonymous = "anonymous"; private static final String authenticated = "authenticated"; private static final String fullyAuthenticated = "fullyAuthenticated"; private static final String rememberMe = "rememberMe"; private final ExpressionInterceptUrlRegistry REGISTRY; //...... /** * Specify that URLs are allowed by anyone. * * @return the {@link ExpressionUrlAuthorizationConfigurer} for further * customization */ public ExpressionInterceptUrlRegistry permitAll() { return access(permitAll); } public ExpressionInterceptUrlRegistry access(String attribute) { if (not) { attribute = "!" + attribute; } interceptUrl(requestMatchers, SecurityConfig.createList(attribute)); return ExpressionUrlAuthorizationConfigurer.this.REGISTRY; } private void interceptUrl(Iterable<? extends RequestMatcher> requestMatchers, Collection<ConfigAttribute> configAttributes) { for (RequestMatcher requestMatcher : requestMatchers) { REGISTRY.addMapping(new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping( requestMatcher, configAttributes)); } } }
permitAll操做將「permitAll」這個attribute以及對應的requestMatchers添加到REGISTRYweb
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/css/**", "/js/**","/fonts/**").permitAll() .anyRequest().authenticated(); } }
這裏重點注意這個anyRequest().authenticated(),能夠看到沒有配置permitAll的請求,都要求authenticated這個級別的,而AnonymousAuthenticationFilter設置的匿名級別只是anonymous。spring
因而咱們的思路就來了,新建一個filter,插入在AnonymousAuthenticationFilter以前,對於免登陸的設置爲authenticatedsegmentfault
public class DemoFilter extends GenericFilterBean { private Object principal = "annoUser"; private List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_ANNO"); @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { private final Map<String,HttpMethod[]> annoPatternMap = new HashMap<String,HttpMethod[]>(){{ //for demo, you can change it and read from db or else put("/index/demo",new HttpMethod[]{HttpMethod.GET}); }}; String uri = ((HttpServletRequest) servletRequest).getRequestURI(); if(annoPatternMap.containsKey(uri)){ if(SecurityContextHolder.getContext().getAuthentication() == null){ SecurityContextHolder.getContext().setAuthentication( createAuthentication((HttpServletRequest) servletRequest)); } }else{ Authentication auth = SecurityContextHolder.getContext().getAuthentication(); System.out.println(auth == null); if(auth != null && auth instanceof UsernamePasswordAuthenticationToken){ if(principal.toString().equals(auth.getPrincipal().toString())){ SecurityContextHolder.getContext().setAuthentication(null); } } } filterChain.doFilter(servletRequest, servletResponse); } protected Authentication createAuthentication(HttpServletRequest request) { UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken( principal, "N/A", authorities); auth.setDetails(authenticationDetailsSource.buildDetails(request)); return auth; } }
這裏建立了一個僞造的UsernamePasswordAuthenticationTokensession
這裏有一點要注意一下,就在判斷不是配置的容許匿名訪問的url的時候,若是以前的token是咱們設置的,則須要從新清空,防止一旦訪問匿名url以後獲取session再去越權訪問其餘沒有配置的url。app
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .addFilterBefore(new DemoFilter(),AnonymousAuthenticationFilter.class) .authorizeRequests() .antMatchers("/css/**", "/js/**","/fonts/**").permitAll() .anyRequest().authenticated(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("admin").password("admin").roles("USER"); } }
在AnonymousAuthenticationFilter以前提早設置好SecurityContextHolder裏頭的authentication。ide
這樣基本就大功告成了,不過有幾點須要注意:ui