2021SC@SDUSC
这次我们继续分析Security模块
SecurityConfig
首先我们看到 SecurityConfig
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ...
}
SecurityConfig上面启用了三个注解,其中第一个注解Configuration不用过多解释,其为声明一个Spring Bean,
@EnableWebSecurity
这个注解的作用是告诉Spring容器,我们有一个Spring Security的配置
@EnableGlobalMethodSecurity
开启全局的方法安全
这个的作用是能够在调用某一个方法之时进行一些安全鉴定工作
包括前置任务和后置任务等
成员
@Autowired
UserDetailsService ds2ManagerUserDetailsService;
这个UserDetailService是自动绑定的,但是并没有在Security模块中发现对应的Bean
观察了其他需要UserDetailService的模块,他们都有一个UserDetailService的实现,却基本没有配置他们的地方。
并且构建项目时需要调用父模块的build,其他子模块单独打包会出现错误
由此可见,这里的UserDetailService在打包时会动态的绑定到对应的模块所提供的UserDetailService,以实现解耦
重载方法
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(ds2ManagerUserDetailsService)
.passwordEncoder(passwordEncoder());
}
该方法告诉容器应该采用哪个用户数据服务,并且给出密码的编码器
编码器是简单的 BCryptPasswordEncoder
@Override
protected void configure(HttpSecurity http) throws Exception {
// 异常处理
http.exceptionHandling().authenticationEntryPoint(restAuthenticationEntryPoint())
.and()
// 放行login,register
.authorizeRequests()
.antMatchers("/login", "/register").permitAll()
.antMatchers("/hello", "/img/get_by_id").permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.and()
// 关闭跨域攻击
.csrf().disable()
// 关闭session处理
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
这个方法中对于一些情况进行了配置,比如说给出了authenticationEntryPoint,允许了一些方法不需要安全检测直接同行,关闭了跨域攻击,关闭了session处理等
下面还声明了Filter
restAuthenticationEntryPoint
RestAuthenticationEntryPoint实现了接口 AuthenticationEntryPoint
的 commence
方法,当用户请求处理遇到了认证异常时,会被 ExceptionTranslationFilter
接住,并且调用 commence
方法来开启特定的认证流程 , 即 authentication schema
security模块中实现的逻辑是直接返回报错信息:
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Cache-Control","no-cache");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.getWriter().println(JSONUtil.parse(CommonResult.unauthorized(authException.getMessage())));
response.getWriter().flush();
}
HttpSecurity.addFilterBefore
这个方法是将你提供的第一个参数对应的Filter加载第二个参数对应的Filter前面
我们可以查看源码:
@Override
public HttpSecurity addFilterBefore(Filter filter, Class<? extends Filter> beforeFilter) {
this.comparator.registerBefore(filter.getClass(), beforeFilter);
return addFilter(filter);
}
compatator是 FilterComparator
的实例
FilterComparator 中有一个有序的filter HashMap,是以class为键,优先级为值
这也意味着每种过滤器都是唯一存在的
FilterComparator() {
Step order = new Step(INITIAL_ORDER, ORDER_STEP);
put(ChannelProcessingFilter.class, order.next());
order.next(); // gh-8105
put(WebAsyncManagerIntegrationFilter.class, order.next());
put(SecurityContextPersistenceFilter.class, order.next());
put(HeaderWriterFilter.class, order.next());
//...
put(UsernamePasswordAuthenticationFilter.class, order.next());
//...
}
order的初始值是100,
每个filter之间间隔了ORDER_STEP - 1个order,用于塞入自定义的filter