本文关注应用的安全方面,涉及校验以及授权方面,以springboot自带的security板块作为讲解的内容

实例

建议用户可直接路由至博主的先前博客spring security整合cas方案。本文则针对相关的源码作下简单的分析,方便笔者以及读者更深入的了解spring的security板块

@EnableWebSecurity

这个注解很精髓,基本上可以作为security的入口,笔者贴一下它的源码

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,SpringWebMvcImportSelector.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;
}

可以分为三个部分来分析,
SpringWebMvcImportSelector-支持mvc的参数安全校验,替代了@EnableWebMvcSecurity注解
WebSecurityConfiguration-Web的安全配置
@EnableGlobalAuthentication-支持公共的认证校验

SpringWebMvcImportSelector

首先先看下其如何整合mvc的安全校验,其是一个ImportSelector接口,观察下其复写的方法

public String[] selectImports(AnnotationMetadata importingClassMetadata) {boolean webmvcPresent = ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet",getClass().getClassLoader());return webmvcPresent? new String[] {"org.springframework.security.config.annotation.web.configuration.WebMvcSecurityConfiguration" }: new String[] {};}

由上述代码可知,在classpath环境中存在mvc的关键类DispatcherServlet时便会引入WebMvcSecurityConfiguration类,那么此类又配置了什么东西呢?
里面的代码很简单,但关键是其是WebMvcConfigurer接口的实现类,根据之前的文章提到,该接口主要是用于配置MVC的相关功能,比如参数处理器、返回值处理器、异常处理器等等。

而该类只是扩展了相应的参数处理器,我们可以看下源码

    @Override@SuppressWarnings("deprecation")public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {// 支持@AuthenticationPrinciple参数注解校验AuthenticationPrincipalArgumentResolver authenticationPrincipalResolver = new AuthenticationPrincipalArgumentResolver();authenticationPrincipalResolver.setBeanResolver(beanResolver);argumentResolvers.add(authenticationPrincipalResolver);// 废弃argumentResolvers.add(new org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver());// csrf token参数argumentResolvers.add(new CsrfTokenArgumentResolver());}

针对@AuthenticationPrinciple注解的参数校验,本文不展开了,这里作下归纳

  1. 带有@AuthenticationPrinciple注解的参数其值会从SecurityContext的上下文读取相应的Authentication校验信息
  2. 有一个要求,被该注解修饰的参数须同SecurityContext的上下文存放的Authentication信息为同一接口,否则则会返回null。如果设置了errorOnInvalidType属性为true,则会抛异常
  3. 综上所述,该注解主要是方便将校验通过的Token用于参数赋值,其它的作用也不是很大

@EnableGlobalAuthentication

再来分析下springboot-security的公共认证校验是什么概念,贴下源码

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}

OK,直接进入相应的AuthenticationConfiguration类进行具体的分析


1.其引入了ObjectPostProcessorConfiguration配置用于创建AutowireBeanFactoryObjectPostProcessor类,作用应该是通过Spring上下文实例相应的实体类并注册到bean工厂中

    @Beanpublic ObjectPostProcessor<Object> objectPostProcessor(AutowireCapableBeanFactory beanFactory) {return new AutowireBeanFactoryObjectPostProcessor(beanFactory);}

2.创建基于密码机制的认证管理器Bean,类型为DefaultPasswordEncoderAuthenticationManagerBuilder

    @Beanpublic AuthenticationManagerBuilder authenticationManagerBuilder(ObjectPostProcessor<Object> objectPostProcessor, ApplicationContext context) {// 密码加密器LazyPasswordEncoder defaultPasswordEncoder = new LazyPasswordEncoder(context);// 认证事件传播器AuthenticationEventPublisher authenticationEventPublisher = getBeanOrNull(context, AuthenticationEventPublisher.class);// 默认的认证管理器DefaultPasswordEncoderAuthenticationManagerBuilder result = new DefaultPasswordEncoderAuthenticationManagerBuilder(objectPostProcessor, defaultPasswordEncoder);if (authenticationEventPublisher != null) {result.authenticationEventPublisher(authenticationEventPublisher);}return result;}

上述的密码加密器支持多种方式的加密,比如bcrypt(默认)/ladp/md5/sha-1等,感兴趣的读者可自行阅读。用户也可多用此Bean作额外的扩展,例如官方建议的如下代码

@Configuration
@EnableGlobalAuthentication
public class MyGlobalAuthenticationConfiguration {@Autowiredpublic void configureGlobal(AuthenticationManagerBuilder auth) {auth.inMemoryAuthentication().withUser("user").password("password").roles("USER").and().withUser("admin").password("password").roles("ADMIN,USER");}}

3.创建基于UserDetails的认证器,用于管理用户的授权信息

    @Beanpublic static InitializeUserDetailsBeanManagerConfigurer initializeUserDetailsBeanManagerConfigurer(ApplicationContext context) {return new InitializeUserDetailsBeanManagerConfigurer(context);}

其会创建基于Datasource源的DaoAuthenticationProvider认证校验器,前提是ApplicationContext上下文存在UserDetailsServiceBean对象,否则会不创建。如果用户想基于数据库或者其他数据源的可尝试复写UserDetailsService接口

@Configuration
public class DaoUserDetailsServiceConfig {/*** load user info by dao** @see org.springframework.security.authentication.dao.DaoAuthenticationProvider*/@Configurationpublic static class DefaultUserDetailsService implements UserDetailsService {private static final String DEFAULT_PASS = "defaultPass";// admin authorityprivate Collection<? extends GrantedAuthority> adminAuthority;@Resourceprivate PasswordEncoder defaultPasswordEncoder;public DefaultUserDetailsService() {SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_ADMIN");List<GrantedAuthority> authorities = new ArrayList<>();authorities.add(authority);adminAuthority = Collections.unmodifiableList(authorities);}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {User userdetails = new User(username, defaultPasswordEncoder.encode(DEFAULT_PASS), adminAuthority);return userdetails;}@Beanpublic PasswordEncoder daoPasswordEncoder() {PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();return passwordEncoder;}}
}

注意:实现UserDetailsService的自定义实例请确保只有一个注册至ApplicationContext上,否则上述的基于数据源配置无法自动化配置;但也可通过AuthenticationManagerBuilder#userDetailsService()方法来进行相应的配置


4.创建AuthenticationProvider认证器,用于用户信息的校验

    @Beanpublic static InitializeAuthenticationProviderBeanManagerConfigurer initializeAuthenticationProviderBeanManagerConfigurer(ApplicationContext context) {return new InitializeAuthenticationProviderBeanManagerConfigurer(context);}

同第三点,只是它就配置简单的AuthenticationProvider至相应的AuthenticationManagerBuilderBean中

所以综上所述,@EnableGlobalAuthentication注解的主要目的是配置认证管理器,里面包含了加密器以及相应的认证器

WebSecurityConfiguration

web方面的安全配置,笔者也根据加载的顺序来进行分析


1.获取WebSecurityConfigurer接口bean集合的AutowiredWebSecurityConfigurersIgnoreParents

    @Beanpublic static AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(ConfigurableListableBeanFactory beanFactory) {return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);}

此Bean用于获取所有注册在bean工厂上的WebSecurityConfigurer接口,用户也一般通过此接口的抽象类WebSecurityConfigurerAdapter来进行相应的扩展


2.设置Security的Filter过滤链配置,提前为创建过滤链作准备

    @Autowired(required = false)public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)throws Exception {// WebSecurity创建webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));if (debugEnabled != null) {webSecurity.debug(debugEnabled);}// 根据@Order属性排序Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE);Integer previousOrder = null;Object previousConfig = null;// 校验Order对应的值,不允许相同,否则会抛出异常for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {Integer order = AnnotationAwareOrderComparator.lookupOrder(config);if (previousOrder != null && previousOrder.equals(order)) {throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of "+ order + " was already used on " + previousConfig + ", so it cannot be used on "+ config + " too.");}previousOrder = order;previousConfig = config;}// 对排序过的SecurityConfigurer依次放入WebSecurity对象中for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {webSecurity.apply(webSecurityConfigurer);}this.webSecurityConfigurers = webSecurityConfigurers;}

这里便提一下,我们在继承WebSecurityConfigurerAdapter抽象类的时候,记得在其头上加上@Order属性,并且保证值唯一


3.创建Security过滤链

    @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)public Filter springSecurityFilterChain() throws Exception {// 如果用户没有配置WebSecurityConfigurer接口,则创建一个空的boolean hasConfigurers = webSecurityConfigurers != null&& !webSecurityConfigurers.isEmpty();if (!hasConfigurers) {WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});webSecurity.apply(adapter);}// create Filterreturn webSecurity.build();}

看来Filter拦截器的配置是通过WebSecurity这个类来完成的,限于里面的代码过于复杂,本文就不展开了,感兴趣的读者可以重点关注下此类。由此可以得出Springboot的安全校验是通过过滤链的设计方式来完成的


4.URI权限校验Bean,其依赖于第三点的配置

    @Bean@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)public WebInvocationPrivilegeEvaluator privilegeEvaluator() throws Exception {return webSecurity.getPrivilegeEvaluator();}

5.安全校验表达式验证Bean,其也依赖于第三点的配置,应该是与第四点搭配使用

    @Bean@DependsOn(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)public SecurityExpressionHandler<FilterInvocation> webSecurityExpressionHandler() {return webSecurity.getExpressionHandler();}

小结

Springboot整合的Security板块内容很多,本文也展示不完,不过值得关注的是以下几个方面
1)WebSecurity的个性化配置类,一般是复写抽象接口WebSecurityConfigurerAdapter,再加上@EnableWebSecurity注解便可

2)AuthenticationManagerBuilder认证校验器,重点关注其中的密码校验器,用于密码的加密解密,默认使用bcrypt方式。如果用户想通过其他数据源获取用户信息,可以关注UserDetailsService接口。推荐用户均使用AuthenticationManagerBuilder类配置认证机制!

3)WebSecurity类,此类是Springboot Security模块的核心类,具体的过滤链配置均是由此类得到的。读者以及笔者应该对此加以关注

转载于:https://www.cnblogs.com/question-sky/p/10084423.html

springboot情操陶冶-web配置(八)相关推荐

  1. springboot情操陶冶-web配置(四)

    承接前文springboot情操陶冶-web配置(三),本文将在DispatcherServlet应用的基础上谈下websocket的使用 websocket websocket的简单了解可见维基百科 ...

  2. springboot情操陶冶-@SpringBootApplication注解解析

    承接前文springboot情操陶冶-@Configuration注解解析,本文将在前文的基础上对@SpringBootApplication注解作下简单的分析 @SpringBootApplicat ...

  3. SpringBoot深入(一)--SpringBoot内置web容器及配置

    版权声明:作者原创,转载请注明出处. 本系列文章目录地址:http://blog.csdn.net/u011961421/article/details/79416510 前言 在学会基本运用Spri ...

  4. Springboot环境下mybatis配置多数据源配置

    mybatis多数据源配置(本文示例为两个),方便实现数据库的读写分离,分库分表功能 本文基于springboot2进行的配置,如版本为springboot1系列则需修改yml的配置(在文末附带) m ...

  5. 轻松搭建基于 SpringBoot Vue 的 Web 商城应用

    背景介绍 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数 ...

  6. Spring Boot——自定义Web配置类后无法访问/static文件夹下静态资源

    问题描述 自定义Web配置类后无法访问 /static文件夹下静态资源. 已加相关依赖包. 官方文档 Spring MVC Auto Configuration Maven <dependenc ...

  7. SpringBoot默认日志logback配置解析

    SpringBoot默认日志logback配置解析 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢 如何引入日志? 日志输出格式 ...

  8. SpringBoot ——Spring Boot日志配置

    Spring Boot 采用了 slf4j+logback 的组合形式,Spring Boot也提供对JUL.log4j2.Logback提供了默认配置 1.默认日志配置 修改日志默认级别 2.修改日 ...

  9. Serverless 实战 —— 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用

    Serverless 实战 -- 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用 背景介绍 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute ...

最新文章

  1. linux压缩和解压命令总结
  2. hdu2067 简单dp或者记忆化搜索
  3. check corners_免费下载:将Mac样式的Hot Corners添加到Windows 10
  4. 王昊奋 | 从聊天机器人到虚拟生命:AI技术的新机遇
  5. 读 利用python进行数据分析 后感
  6. 结构体,宏,枚举,函数,指针
  7. 《Redis实战》一2.2 使用Redis实现购物车
  8. 机器学习 数据间的定义_定义数据科学,机器学习和人工智能
  9. STM32开发环境配置
  10. 【实用软件】多功能游戏工具箱-Watt Toolkit
  11. 【新能源】新能源之锂电池产业链梳理
  12. 计算机flash拉开效果,使用Flash制作卷轴展开效果
  13. Coursera Algorithm Ⅱ week4 编程作业 Boggle
  14. 用Python做一个会旋转的五彩风筝
  15. 王道P41 T23(单链表实现)
  16. 读书笔记:《流畅的Python》第19章 动态属性和特性
  17. 艾特网能“高效节能三板斧”亮相第22届机房协会年会
  18. Android自带模拟器设置Proxy
  19. NOI2016 day1 总(xia)结(che)
  20. 骨架屏 之 Vue SSR(快捷简易版本解决方案)

热门文章

  1. 华为“造车”,为时未晚
  2. 计算机视觉入门之构建一个扫描仪
  3. 新的起点,新的征程,新的未来
  4. redis查看端口号命令
  5. Centos 系统 FTP服务器搭建
  6. 进入mysql命令行之后,怎么退出
  7. C++课后习题第七章
  8. macOS 关于 VMware Fusion 键盘鼠标失灵的问题
  9. java计算机毕业设计在线教育资源管理系统源码+数据库+lw文档+系统+部署
  10. 15- APP测试面试题上