在分析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. Robust Principal Component Analysis?(PCP)

    目录 引 一些微弱的假设: 问题的解决 理论 去随机 Dual Certificates(对偶保证?) Golfing Scheme 数值实验 代码 Candes E J, Li X, Ma Y, e ...

  2. Flutter控制屏幕旋转

    特定页面旋转屏幕很简单: SystemChrome.setPreferredOrientations([ ... ]); 数组中是您要支持的屏幕方向. 如果想在特定页面固定横屏, 您可以这样写: @o ...

  3. XML fragments parsed from previous mappers already contains value for xxxxx

    错误信息: Caused by: org.springframework.core.NestedIOException: Failed to parse mapping resource: 'file ...

  4. python 所有常用模块汇总

    time:时间 时间戳(timestamp):time.time() 延迟线程的运行:time.sleep(secs) (指定时间戳下的)当前时区时间:time.localtime([secs]) ( ...

  5. linux shell通配符及if语句判断

    $# 是传给脚本的参数个数 $0 是脚本本身的名字$1 是传递给该shell脚本的第一个参数$2 是传递给该shell脚本的第二个参数$@ 是传给脚本的所有参数的列表$* 是以一个单字符串显示所有向脚 ...

  6. MySQL数据库开发的三十六条军规

    一.核心军规 尽量不在数据库做运算,cpu计算的事务必移至业务层; 控制表.行.列数量([控制单张表的数据量 1年/500W条,超出可做分表],[单库表数据量不超过300张] .[单张表的字段个数不超 ...

  7. loj2977 巧克力 (斯坦纳树+随机化)

    考虑颜色比较少的时候,第一问可以直接斯坦纳树 第二问考虑二分,每次把每格的权值给成1000+[a[i]>m],就是在个数最少的基础上尽量选小于等于m的 然而颜色太多不能直接做,但可以把每种颜色映 ...

  8. yii2 命令行执行php命令 commands(命令)

    YII2可以在命令行执行php命令,作为半路出家的撩妹君可谓是抠脚福音.作为一个屌丝级的程序员必须要有智能提示代码的IDE,比如PHPstorm.至于如何免费使用嘛..... 首先明白YII2自带的c ...

  9. Spring Cloud 微服务

    https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw==&mid=2247486301&idx=2&sn=f6d45860269b61 ...

  10. ASP.NET and ADO.NET

    1.ASP.NET ASP.NET是一个使用HTML.Css.JacaScript  和服务器脚本创建网页和网站的开发框架 ASP.NET支持 WebPages.MVC.WebForms三种开发模式 ...