springboot情操陶冶-web配置(八)
本文关注应用的安全方面,涉及校验以及授权方面,以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
注解的参数校验,本文不展开了,这里作下归纳
- 带有@AuthenticationPrinciple注解的参数其值会从SecurityContext的上下文读取相应的Authentication校验信息
- 有一个要求,被该注解修饰的参数须同SecurityContext的上下文存放的Authentication信息为同一接口,否则则会返回null。如果设置了errorOnInvalidType属性为true,则会抛异常
- 综上所述,该注解主要是方便将校验通过的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配置(八)相关推荐
- springboot情操陶冶-web配置(四)
承接前文springboot情操陶冶-web配置(三),本文将在DispatcherServlet应用的基础上谈下websocket的使用 websocket websocket的简单了解可见维基百科 ...
- springboot情操陶冶-@SpringBootApplication注解解析
承接前文springboot情操陶冶-@Configuration注解解析,本文将在前文的基础上对@SpringBootApplication注解作下简单的分析 @SpringBootApplicat ...
- SpringBoot深入(一)--SpringBoot内置web容器及配置
版权声明:作者原创,转载请注明出处. 本系列文章目录地址:http://blog.csdn.net/u011961421/article/details/79416510 前言 在学会基本运用Spri ...
- Springboot环境下mybatis配置多数据源配置
mybatis多数据源配置(本文示例为两个),方便实现数据库的读写分离,分库分表功能 本文基于springboot2进行的配置,如版本为springboot1系列则需修改yml的配置(在文末附带) m ...
- 轻松搭建基于 SpringBoot Vue 的 Web 商城应用
背景介绍 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数 ...
- Spring Boot——自定义Web配置类后无法访问/static文件夹下静态资源
问题描述 自定义Web配置类后无法访问 /static文件夹下静态资源. 已加相关依赖包. 官方文档 Spring MVC Auto Configuration Maven <dependenc ...
- SpringBoot默认日志logback配置解析
SpringBoot默认日志logback配置解析 前言 今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢 如何引入日志? 日志输出格式 ...
- SpringBoot ——Spring Boot日志配置
Spring Boot 采用了 slf4j+logback 的组合形式,Spring Boot也提供对JUL.log4j2.Logback提供了默认配置 1.默认日志配置 修改日志默认级别 2.修改日 ...
- Serverless 实战 —— 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用
Serverless 实战 -- 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用 背景介绍 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute ...
最新文章
- linux压缩和解压命令总结
- hdu2067 简单dp或者记忆化搜索
- check corners_免费下载:将Mac样式的Hot Corners添加到Windows 10
- 王昊奋 | 从聊天机器人到虚拟生命:AI技术的新机遇
- 读 利用python进行数据分析 后感
- 结构体,宏,枚举,函数,指针
- 《Redis实战》一2.2 使用Redis实现购物车
- 机器学习 数据间的定义_定义数据科学,机器学习和人工智能
- STM32开发环境配置
- 【实用软件】多功能游戏工具箱-Watt Toolkit
- 【新能源】新能源之锂电池产业链梳理
- 计算机flash拉开效果,使用Flash制作卷轴展开效果
- Coursera Algorithm Ⅱ week4 编程作业 Boggle
- 用Python做一个会旋转的五彩风筝
- 王道P41 T23(单链表实现)
- 读书笔记:《流畅的Python》第19章 动态属性和特性
- 艾特网能“高效节能三板斧”亮相第22届机房协会年会
- Android自带模拟器设置Proxy
- NOI2016 day1 总(xia)结(che)
- 骨架屏 之 Vue SSR(快捷简易版本解决方案)