在分析SpringSecurity前,基于多年前使用SpringSecurity和近年来使用Shiro的经验, SpringSecurity这些年在发展和SpringBoot整合之后,也逃不出以下的一些套路:

1. 提供一个AuthenticationManager,用于登录认证

2. 提供一个web的过滤器链,用于保证web请求的安全处理,这个过滤器链中会包括判断用户是否登录,处理用户的认证请求,基于URL的路径检查用户是否能够访问特定的请求等过滤器

3. 提供一个获取用户数据的接口实现

4. 提供一个方法拦截器,用于基于方法的细粒度的授权控制

以上的1、2、3项都是必要的配置,4是增强级配置可以没有

下面我们来看下 SpringSecurity 如何来完成上述1、2、3的配置

一. 上文提到过 org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter 这个类,springboot只要类路径下能找到 WebSecurityConfigurer 接口的实现类后,就不会加载相应的默认配置。 通过重写一些方法来覆盖默认的一些配置


@Configuration
@EnableWebSecurity
public class FormLoginSecurityConfig extends WebSecurityConfigurerAdapter {


@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin(); //拦截所有URL的访问,将不具备USER角色的用户将被导航到登录页
}


@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  auth.inMemoryAuthentication().withUser("user").password("password").roles("USER"); //基于内存的用户认证
}
}

 

从上面这个例子可以看出,我们自己实现的子类能够做这些事:

  • 基于url的路径检查哪些当前的访问是不是具备需要的权限(角色),如果不具备相应的角色,则将其导航至表单认证页面
  • 基于AuthenticationManagerBuilder 调用其不同方法实现不同的认证机制

这样基本能解决授权和认证,但实际使用时我们不会用例子中的内存数据去完成用户认证,而是通过访问后台的数据库等方式去完成认证,所以还需要配置合适的认证管理器AuthenticationManager和合适的获取用户数据的接口UserDetailsService的实现,下面是AuthenticationManager接口和UserDetailsService的源码:

public interface AuthenticationManager {

    Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
public interface UserDetailsService {

    UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; // 用于通过用户名获取用户信息
}

二 . 我们发现除了上文提到的SecurityAutoConfiguration自动配置类外,Springboot 还在 spring.factorys 提供UserDetailsServiceAutoConfiguration类,这个配置类中配置了

UserDetailsService接口的bean实现UserDetailsService, 这是一个基于内存用户数据的实现,当然这是一个默认配置,所以我们只要提供了UserDetailsService接口的bean配置,就将覆盖默认的获取用户的方式
@Configuration
@ConditionalOnClass(AuthenticationManager.class)
@ConditionalOnBean(ObjectPostProcessor.class)
@ConditionalOnMissingBean({ AuthenticationManager.class, AuthenticationProvider.class,
UserDetailsService.class })
public class UserDetailsServiceAutoConfiguration { private static final String NOOP_PASSWORD_PREFIX = "{noop}"; private static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern
.compile("^\\{.+}.*$"); private static final Log logger = LogFactory
.getLog(UserDetailsServiceAutoConfiguration.class); @Bean
@ConditionalOnMissingBean(type = "org.springframework.security.oauth2.client.registration.ClientRegistrationRepository")
@Lazy
public InMemoryUserDetailsManager inMemoryUserDetailsManager(
SecurityProperties properties,
ObjectProvider<PasswordEncoder> passwordEncoder) {
SecurityProperties.User user = properties.getUser();
List<String> roles = user.getRoles();
return new InMemoryUserDetailsManager(User.withUsername(user.getName())
.password(getOrDeducePassword(user, passwordEncoder.getIfAvailable()))
.roles(StringUtils.toStringArray(roles)).build());
} private String getOrDeducePassword(SecurityProperties.User user,
PasswordEncoder encoder) {
String password = user.getPassword();
if (user.isPasswordGenerated()) {
logger.info(String.format("%n%nUsing generated security password: %s%n",
user.getPassword()));
}
if (encoder != null || PASSWORD_ALGORITHM_PATTERN.matcher(password).matches()) {
return password;
}
return NOOP_PASSWORD_PREFIX + password;
} }

三. 通过上述的分析,认证的用户数据来源和基于对url资源的访问授权检查的配置都有了,就欠缺一个过滤器链了,可以得出这个过滤器链也是有默认配置的,在上文中介绍过

SecurityAutoConfiguration这个配置类会导入三个配置类  SpringBootWebSecurityConfiguration.class ,  WebSecurityEnablerConfiguration.class, SecurityDataConfiguration. 上文分析了SpringBootWebSecurityConfiguration,现在分析下 WebSecurityEnablerConfiguration ,还是看源码:

@Configuration
@ConditionalOnBean(WebSecurityConfigurerAdapter.class)
@ConditionalOnMissingBean(name = BeanIds.SPRING_SECURITY_FILTER_CHAIN)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration { }

通过源码发现引入了 @EnableWebSecurity ,再看EnableWebSecurity源码:

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
SpringWebMvcImportSelector.class,
OAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity { /**
* Controls debugging support for Spring Security. Default is false.
* @return if true, enables debug support with Spring Security
*/
boolean debug() default false;
}

又发现导入了 WebSecurityConfiguration.class ,在这个类中有如下配置:

/**
* Creates the Spring Security Filter Chain
* @return the {@link Filter} that represents the security filter chain
* @throws Exception
*/
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
webSecurity.apply(adapter);
}
return webSecurity.build();
}

这也就是springSecurity 默认帮我们配置的过滤器链的bean ,先通过写一个单元测试,看看这个默认帮我们配置的过滤器链的bean 里面都包含了哪些过滤器:

@RunWith(SpringRunner.class)
@SpringBootTest(classes=App.class)
public class FilterChainProxyTest {
@Autowired
FilterChainProxy chain ; @Test
public void test() {
SecurityFilterChain filterChain = chain.getFilterChains().get(0) ;
List<Filter> filters = filterChain.getFilters() ;
for(Filter filter:filters) {
System.out.println( filter.getClass().getSimpleName() );
}
} }

执行后输出:

WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
CsrfFilter
LogoutFilter
UsernamePasswordAuthenticationFilter
DefaultLoginPageGeneratingFilter
DefaultLogoutPageGeneratingFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor


默认竟然在链中配置了15个过滤器,已经考虑得很周全了, 所以这个bean一般情况下我们不需要去自定义配置,我们可以通过对WebSecurityConfigurerAdapter 中一些方法的重写来改变这个过滤器链中的内容,从而达到定制的目的就可以了。

SpringSecurity的配置分析的更多相关文章

  1. SpringSecurity相关配置【SpringSecurityConfig】

    SpringSecurity的配置相对来说有些复杂,如果是完整的bean配置,则需要配置大量的bean,所以xml配置时使用了命名空间来简化配置,同样,spring为我们提供了一个抽象类WebSecu ...

  2. vue-cil 中的配置分析

    自己写过配置分析,但是看了这位同学的文章之后发现写的比我全和细,索性直接转载过来了. 转自http://www.cnblogs.com/libin-1/p/6596810.html

  3. Istio 的配置分析

    Istio 的配置分析 目录 Istio 的配置分析 Analyzer 的消息格式 ConflictingMeshGatewayVirtualServiceHosts 问题解决 举例 Conflict ...

  4. 嵌入式Linux驱动学习之路(三)u-boot配置分析

    u-boot配置流程分析 执行make tiny4412_config后,将会对u-boot进行一些列的配置,以便于后面的编译. 打开顶层目录下的Makefile,查找对于的规则tiny4412_co ...

  5. u-boot 之配置分析 (2)

    Makefile简要分析所有这些目录的编译连接都是由顶层目录的makefile来确定的. 1.在makefile中有: unconfig: @rm -f $(obj)include/config.h ...

  6. STM32F4时钟配置分析

    //学习STM32F4的过程中关于时钟上面讲的比较好 特地转发与大家分享 STM32F4时钟设置分析 原文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明. 环 ...

  7. 【玩转开源】BananaPi R2 —— 第二篇 Openwrt 网口配置分析

    上次和大家分享了如何烧录和安装Openwrt到BananaPi R2,运行Openwrt的R2目前就具备路由器的功能了,这次我们来看看R2运行Openwrt的性能如何,同时也会讲解一些常用的网络知识. ...

  8. 从0移植uboot (一) _配置分析

    来源:Linux社区  作者:xiaojiang1025  :http://www.linuxidc.com/Linux/2017-02/141018.htm 和绝大多数源码编译安装一样,uboot的 ...

  9. Servlet各种路径、URL配置分析

    大家都知道,Servlet有个配置: <servlet> <servlet-name>zolltyMVC</servlet-name> <servlet-cl ...

随机推荐

  1. Smart Indenter for VBE(64bits smart indent addin for VBA Editor),VBA开发必备的智能排版工具。

    原始出处:www.cnblogs.com/Charltsing/p/SmartIndenter64.html 作者QQ: 564955427 最近更换电脑,改用64位office做开发.VBA代码美化 ...

  2. 【问题解决方案】查看Python安装了哪些库(pandas, matplotlib等等)

    查看方法: 一句命令:cmd打开终端后键入pip list END

  3. css 3 新特性

    CSS3的新特性大致分为以下六类 1.CSS3选择器 2.CSS3边框与圆角 3.CSS3背景与渐变 4.CSS3过渡 5.CSS3变换 6.CSS3动画 下面分别说一说以上六类都有哪些内容 CSS3 ...

  4. POJ1847 Tram

    Tram Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 20274   Accepted: 7553 Description ...

  5. Vs2015 当前不会命中断点,没有与此关联的可执行代码

    在学习Civil 3D本地化包程序的过程中, 使用.Net Reflector调试本地化包的主程序CountryKits.dll, .Net Reflector创建了相应的pdb文件等, 在我反编译并 ...

  6. Mint-UI Picker 三级联动

    Mint-UI Picker组件的三级联动 HTML: <mt-picker :slots="slots" value-key="name" @chang ...

  7. Linux keepalived工作原理

    keepalived简介与工作原理 Keepalived的作用是检测服务器的状态,如果有一台web服务器宕机,或工作出现故障,Keepalived将检测到,并将有故障的服务器从系统中剔除,同时使用其他 ...

  8. UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 0: ordinal not in range(128)

  9. ios端position为fixed失效的解决办法

    关键代码 document.getElementById("searchInputbox").addEventListener('touchmove', handler, {pas ...

  10. CF700E E. Cool Slogans

    https://codeforces.com/contest/700/problem/E 题解:https://www.luogu.org/problemnew/solution/CF700E 其实就 ...