Spring Security (三) 核心配置解读
上一篇文章《Spring Security(二)--Guides》,通过Spring Security的配置项了解了Spring Security是如何保护我们的应用的,本篇文章对上一次的配置做一个分析。
3 核心配置解读
3.1 功能介绍
这是Spring Security入门指南中的配置项:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin").roles("USER");
}
}
当配置了上述的javaconfig之后,我们的应用便具备了如下的功能:
- 除了“/”,"/home"(首页),"/login"(登录),"/logout"(注销),之外,其他路径都需要认证。
- 指定“/login”该路径为登录页面,当未认证的用户尝试访问任何受保护的资源时,都会跳转到“/login”。
- 默认指定“/logout”为注销页面
- 配置一个内存中的用户认证器,使用admin/admin作为用户名和密码,具有USER角色
- 防止CSRF攻击
- Session Fixation protection(可以参考我之前讲解Spring Session的文章,防止别人篡改sessionId)
- Security Header(添加一系列和Header相关的控制)
- HTTP Strict Transport Security for secure requests
- 集成X-Content-Type-Options
- 缓存控制
- 集成X-XSS-Protection
- X-Frame-Options integration to help prevent Clickjacking(iframe被默认禁止使用)
- 为Servlet API集成了如下的几个方法
- HttpServletRequest#getRemoteUser()
- HttpServletRequest.html#getUserPrincipal()
- HttpServletRequest.html#isUserInRole(java.lang.String)
- HttpServletRequest.html#login(java.lang.String, java.lang.String)
- HttpServletRequest.html#logout()
3.2 @EnableWebSecurity
我们自己定义的配置类WebSecurityConfig加上了@EnableWebSecurity注解,同时继承了WebSecurityConfigurerAdapter。你可能会在想谁的作用大一点,毫无疑问@EnableWebSecurity起到决定性的配置作用,它其实是个组合注解。
@Import({ WebSecurityConfiguration.class, // <2>
SpringWebMvcImportSelector.class }) // <1>
@EnableGlobalAuthentication // <3>
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;
}
@Import是springboot提供的用于引入外部的配置的注解,可以理解为:@EnableWebSecurity注解激活了@Import注解中包含的配置类。
<1> SpringWebMvcImportSelector
的作用是判断当前的环境是否包含springmvc,因为spring security可以在非spring环境下使用,为了避免DispatcherServlet的重复配置,所以使用了这个注解来区分。
<2> WebSecurityConfiguration
顾名思义,是用来配置web安全的,下面的小节会详细介绍。
<3> @EnableGlobalAuthentication
注解的源码如下:
@Import(AuthenticationConfiguration.class)
@Configuration
public @interface EnableGlobalAuthentication {
}
注意点同样在@Import之中,它实际上激活了AuthenticationConfiguration这样的一个配置类,用来配置认证相关的核心类。
也就是说:@EnableWebSecurity完成的工作便是加载了WebSecurityConfiguration,AuthenticationConfiguration这两个核心配置类,也就此将spring security的职责划分为了配置安全信息,配置认证信息两部分。
WebSecurityConfiguration
在这个配置类中,有一个非常重要的Bean被注册了。
@Configuration
public class WebSecurityConfiguration {
//DEFAULT_FILTER_NAME = "springSecurityFilterChain"
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
...
}
}
在未使用springboot之前,大多数人都应该对“springSecurityFilterChain”这个名词不会陌生,他是spring security的核心过滤器,是整个认证的入口。在曾经的XML配置中,想要启用spring security,需要在web.xml中进行如下配置:
<!-- Spring Security -->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
而在springboot集成之后,这样的XML被java配置取代。WebSecurityConfiguration中完成了声明springSecurityFilterChain的作用,并且最终交给DelegatingFilterProxy这个代理类,负责拦截请求(注意DelegatingFilterProxy这个类不是spring security包中的,而是存在于web包中,spring使用了代理模式来实现安全过滤的解耦)。
AuthenticationConfiguration
@Configuration
@Import(ObjectPostProcessorConfiguration.class)
public class AuthenticationConfiguration {
@Bean
public AuthenticationManagerBuilder authenticationManagerBuilder(
ObjectPostProcessor<Object> objectPostProcessor) {
return new AuthenticationManagerBuilder(objectPostProcessor);
}
public AuthenticationManager getAuthenticationManager() throws Exception {
...
}
}
AuthenticationConfiguration的主要任务,便是负责生成全局的身份认证管理者AuthenticationManager。还记得在《Spring Security(一)--Architecture Overview》中,介绍了Spring Security的认证体系,AuthenticationManager便是最核心的身份认证管理器。
3.3 WebSecurityConfigurerAdapter
适配器模式在spring中被广泛的使用,在配置中使用Adapter的好处便是,我们可以选择性的配置想要修改的那一部分配置,而不用覆盖其他不相关的配置。WebSecurityConfigurerAdapter中我们可以选择自己想要修改的内容,来进行重写,而其提供了三个configure重载方法,是我们主要关心的:
由参数就可以知道,分别是对AuthenticationManagerBuilder,WebSecurity,HttpSecurity进行个性化的配置。
HttpSecurity常用配置
@Configuration
@EnableWebSecurity
public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/about").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().authenticated()
.and()
.formLogin()
.usernameParameter("username")
.passwordParameter("password")
.failureForwardUrl("/login?error")
.loginPage("/login")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/index")
.permitAll()
.and()
.httpBasic()
.disable();
}
}
上述是一个使用Java Configuration配置HttpSecurity的典型配置,其中http作为根开始配置,每一个and()对应了一个模块的配置(等同于xml配置中的结束标签),并且and()返回了HttpSecurity本身,于是可以连续进行配置。他们配置的含义也非常容易通过变量本身来推测,
- authorizeRequests()配置路径拦截,表明路径访问所对应的权限,角色,认证信息。
- formLogin()对应表单认证相关的配置
- logout()对应了注销相关的配置
- httpBasic()可以配置basic登录
- etc
他们分别代表了http请求相关的安全配置,这些配置项无一例外的返回了Configurer类,而所有的http相关配置可以通过查看HttpSecurity的主要方法得知:
需要对http协议有一定的了解才能完全掌握所有的配置,不过,springboot和spring security的自动配置已经足够使用了。其中每一项Configurer(e.g.FormLoginConfigurer,CsrfConfigurer)都是HttpConfigurer的细化配置项。
WebSecurityBuilder
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
}
以笔者的经验,这个配置中并不会出现太多的配置信息。
AuthenticationManagerBuilder
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin").roles("USER");
}
}
想要在WebSecurityConfigurerAdapter中进行认证相关的配置,可以使用configure(AuthenticationManagerBuilder auth)暴露一个AuthenticationManager的建造器:AuthenticationManagerBuilder 。如上所示,我们便完成了内存中用户的配置。
细心的朋友会发现,在前面的文章中我们配置内存中的用户时,似乎不是这么配置的,而是:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin").roles("USER");
}
}
如果你的应用只有唯一一个WebSecurityConfigurerAdapter,那么他们之间的差距可以被忽略,从方法名可以看出两者的区别:使用@Autowired注入的AuthenticationManagerBuilder是全局的身份认证器,作用域可以跨越多个WebSecurityConfigurerAdapter,以及影响到基于Method的安全控制;而 protectedconfigure()
的方式则类似于一个匿名内部类,它的作用域局限于一个WebSecurityConfigurerAdapter内部。关于这一点的区别,可以参考我曾经提出的issuespring-security#issues4571。官方文档中,也给出了配置多个WebSecurityConfigurerAdapter的场景以及demo,将在该系列的后续文章中解读。
- Java多线程详解4【面试+工作】
- Java多线程详解5【面试+工作】
- Java多线程详解6【面试+工作】
- MySQL备份恢复第二篇(r5笔记第6天)
- SpringMVC 中配置 Swagger 插件.
- MySQL和Oracle对比学习之事务(r5笔记第4天)
- 【面试宝典】Java如何打印数组
- MySQL数据导入导出牛刀小试(r5笔记第3天)
- SpringMVC 异常处理.
- 一条简单的sql在11g和12c中的不同(r5笔记第2天)
- 浅析 SpringMVC 原理和配置.
- 使用impdp不当导致的数据丢失问题(r5笔记第1天)
- MySQL数据库 Event 定时执行任务.
- Tomcat 日志分割.
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 【收藏向】常用Java排错工具单
- MYSQL数据同步之基于GTID事务数据同步
- 【风险通告】XXL-JOB远程命令执行漏洞
- MySQL8.0特性之redo logging动态开关
- 3分钟短文:Laravel模型集合跟基类真不一样,别混为一谈
- 3分钟短文:Laravel模型一对一一对多关系真的乱吗?
- 3分钟短文:Laravel请求对象方法极多,可不是花拳绣腿
- 3分钟短文:Laravel验证用户输入,不要把啥都存到系统里
- 3分钟短文:Laravel用户自定义命令行简明教程
- 3分钟短文:Laravel命令行参数和可选项分不清?怎么可能!
- 《Offer一箩筐》求职之前你必须知道的 4 件事!!
- 3分钟短文:有趣的Laravel命令行交互,输入和输出!
- MySQL limit导致的执行计划差异
- 3分钟短文:用Laravel的方式管理服务器的文件们
- 漫画:什么是 “抽象工厂模式” ?