创建项目
创建一个Springboot web项目,并写一个简单的hello控制器,其行为只需要简单返回一个响应即可,例如:
@RestController
public class HelloController {
@RequestMapping("/hello")
public JsonResult hello() {
return JsonResult.OK();
}
}
运行它,请求 /hello,会返回响应,注意此时没有任何权限机制对请求进行限制,也就是任何人都可以访问/hello资源。
引入依赖
<dependency>
<groupId>
org.springframework.boot
</groupId>
<artifactId>
spring-boot-starter-security
</artifactId>
<version>
2.6.7
</version>
</dependency>
默认加载
在引入Security后如果不做改动,Spring框架会在运行时自动加载Security并运行默认机制,效果就是Security会将整个项目请求保护起来。重新运行应用并访问/hello,浏览器不再直接返回响应,而是跳转到/login并显示一个默认的登录页面,Security起作用了!
发生了什么
Spring会自动加载Security默认安全机制,在请求发生后和Servlet处理请求前使用各种Filter处理这次请求,其中就包括Security框架所包含的Filter。下面代码告诉了我们默认机制发生了什么
@Configuration(
proxyBeanMethods = false
)
@ConditionalOnDefaultWebSecurity
static class SecurityFilterChainConfiguration {
SecurityFilterChainConfiguration() {
}
@Bean
@Order(2147483642)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
((AuthorizedUrl)http.authorizeRequests().anyRequest()).authenticated();
http.formLogin();
http.httpBasic();
return (SecurityFilterChain)http.build();
}
}
http的请求要开启权限保护(authorizaRequests()),哪些请求要保护?任何请求(anyRequest()),这些请求都要是已认证的(authenticated),通过什么方式认证,通过表单认证(formLogin())或Basic认证(httpBasic())——这是我基于教程的理解
注解@ConditionalOnDefaultWebSecurity
是对defaultSecurityFilterChain
方法在什么条件下生效的声明,进入注解看到
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional({DefaultWebSecurityCondition.class})
public @interface ConditionalOnDefaultWebSecurity {
}
@Conditional
注解说明ConditionalOnDefaultWebSecurity
的使用条件是DefaultWebSecurityCondition
,再进入DefaultWebSecurityCondition
查看一下
class DefaultWebSecurityCondition extends AllNestedConditions {
DefaultWebSecurityCondition() {
super(ConfigurationPhase.REGISTER_BEAN);
}
@ConditionalOnMissingBean({WebSecurityConfigurerAdapter.class, SecurityFilterChain.class})
static class Beans {
Beans() {
}
}
@ConditionalOnClass({SecurityFilterChain.class, HttpSecurity.class})
static class Classes {
Classes() {
}
}
}
DefaultWebSecurityCondition
在两种条件下生效,在当前类路径中存在某些类定义的时候(@ConditionalOnClass)SecurityFilterChain.class
或HttpSecurity.class
的时候,和(在现有工厂中)当不存在某些Bean的实例时候(@ConditionalOnMissingBean)不存在WebSecurityConfigurerAdapter.class
或SecurityFilterChain.class
的时候。在引入依赖后,并没有自己定义WebSecurityConfigurerAdapter
和SecurityFilterChain
,因此刚才的过滤链满足了条件,起了作用,产生了效果。
总结一下,Security默认使用了defaultSecurityFilterChain
(中的配置)进行安全行为,如果希望改变默认行为,需要自行定义WebSecurityConfigurerAdapter
或SecurityFilterChain
。定义的方法是创建自己的类继承并注解,使具体实现类在Spring容器中生效。Spring Security 推荐覆盖WebSecurityConfigurerAdapter
。
bilibili - 编程不良人 - SpringSecurity最新实战