网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要体系化学习资料的朋友,可以加我V获取:vip204888 (备注网络安全)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
在此注解接口定义中引入了 WebSecurityConfiguration
3、WebSecurityConfiguration
3.1、setFilterChainProxySecurityConfigurer方法
重点:
1、将自定义的安全配置类对象注入到Spring容器中;
2、构建WebSecurity对象
说明:
1、获取安全配置,通过@value的方式实现了AutowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers();
2、获取类型为WebSecurityConfigurer类及其子类匹配的bean,包括WebSecurityConfigurerAdapter、继承WebSecurityConfigurerAdapter的自定义安全配置类
1)、通过@value(“#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}”)获取安全配置
2)、调用org.springframework.security.config.annotation.web.configuration.AutowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
if (this.debugEnabled != null) {
this.webSecurity.debug(this.debugEnabled);
}
webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);
Integer previousOrder = null;
Object previousConfig = null;
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;
}
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
this.webSecurity.apply(webSecurityConfigurer);
}
this.webSecurityConfigurers = webSecurityConfigurers;
}
3.2、springSecurityFilterChain方法
说明:
1、通过@Bean将springSecurityFilterChain()方法构建的Filter实例对象按名称为springSecurityFilterChain的Bean注入到Spring容器中
2、WebSecurity.build方法会启动对象的配置,重点是: 【可以调用到自定义安全配置类的配置方法】实现自定义配置认证退出处理类、不用认证url等SpringBoot Security安全配置
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT\_FILTER\_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
Assert.state(!(hasConfigurers && hasFilterChain),
"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");
if (!hasConfigurers && !hasFilterChain) {
WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
this.webSecurity.apply(adapter);
}
for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {
this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);
for (Filter filter : securityFilterChain.getFilters()) {
if (filter instanceof FilterSecurityInterceptor) {
this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);
break;
}
}
}
for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {
customizer.customize(this.webSecurity);
}
return this.webSecurity.build();
}
4、自定义安全配置类
自定义安全配置类继承WebSecurityConfigurerAdapter,以对象名为authenticationManager的bean将AuthenticationManager对象注入到Spring容器中
《authenticationManager的bean对象注入流程源码分析图》
说明:
1、以@Bean的方式将AuthenticationManager的Bean以Id="authenticationManager"注入到Spring容器中;
2、调用父类WebSecurityConfigurerAdapter的authenticationManagerBean()方法
重点: 通过authenticationManagerBean()方法实现了将ProviderManager对象做为AuthenticationManager的实例对象,参照 第二章节->2、调用Spring Security安全认证方法中的《将ProviderManager对象做为authenticationManager的bean对象流程源码分析图》
自定义安全配置类源码
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
import cn.edu.tit.ipaddress.ms.framework.config.properties.PermitAllUrlProperties;
import cn.edu.tit.ipaddress.ms.framework.security.filter.JwtAuthenticationTokenFilter;
import cn.edu.tit.ipaddress.ms.framework.security.handle.AuthenticationEntryPointImpl;
import cn.edu.tit.ipaddress.ms.framework.security.handle.LogoutSuccessHandlerImpl;
/\*\*
\* spring security配置
\*
\* @author ruoyi
\*/
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
/\*\*
\* 自定义用户认证逻辑
\*/
@Autowired
private UserDetailsService userDetailsService;
/\*\*
\* 认证失败处理类
\*/
@Autowired
private AuthenticationEntryPointImpl unauthorizedHandler;
/\*\*
\* 退出处理类
\*/
@Autowired
private LogoutSuccessHandlerImpl logoutSuccessHandler;
/\*\*
\* token认证过滤器
\*/
@Autowired
private JwtAuthenticationTokenFilter authenticationTokenFilter;
/\*\*
\* 跨域过滤器
\*/
@Autowired
private CorsFilter corsFilter;
/\*\*
\* 允许匿名访问的地址
\*/
@Autowired
private PermitAllUrlProperties permitAllUrl;
/\*\*
\* 解决 无法直接注入 AuthenticationManager
\*
\* @return
\* @throws Exception
\*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
/\*\*
\* anyRequest | 匹配所有请求路径
\* access | SpringEl表达式结果为true时可以访问
\* anonymous | 匿名可以访问
\* denyAll | 用户不能访问
\* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
\* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
\* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
\* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
\* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
\* hasRole | 如果有参数,参数表示角色,则其角色可以访问
\* permitAll | 用户可以任意访问
\* rememberMe | 允许通过remember-me登录的用户访问
\* authenticated | 用户登录后可访问
\*/
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception
{
// 注解标记允许匿名访问的url
ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();
permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());
httpSecurity
// CSRF禁用,因为不使用session
.csrf().disable()
// 禁用HTTP响应标头
.headers().cacheControl().disable().and()
// 认证失败处理类
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
// 基于token,所以不需要session
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// 过滤请求
.authorizeRequests()
// 对于登录login 注册register 验证码captchaImage 允许匿名访问
.antMatchers("/login","/loginWeixin","/register", "/captchaImage").permitAll()
// 静态资源,可匿名访问
.antMatchers(HttpMethod.GET, "/", "/\*.html", "/\*\*/\*.html", "/\*\*/\*.css", "/\*\*/\*.js", "/profile/\*\*").permitAll()
.antMatchers("/swagger-ui.html", "/swagger-resources/\*\*", "/webjars/\*\*", "/\*/api-docs", "/druid/\*\*").permitAll()
// 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
.and()
.headers().frameOptions().disable();
// 添加Logout filter
httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
// 添加JWT filter
httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
// 添加CORS filter
httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
}
/\*\*
\* 强散列哈希加密实现
\*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder()
{
return new BCryptPasswordEncoder();
}
/\*\*
\* 身份认证接口
\*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
}
二、SpringBoot Security认证流程
1、在用户登录认证类中自动注入AuthenticationManager对象
自动注入AuthenticationManager对象
@Resource
private AuthenticationManager authenticationManager;
@Resource注解-说明:
一、@Resource和@Autowired异同
@Resoutce注解的功能和@Autowired相似的,可以互相替换,一般情况是可以正常运行的,由> @Resource标注的属性也会进行自动装配二、二者区别:
1.提供者不同:
@AutoWired是Spring提供的
@Resource是由Java提供的2.注入规则不同:
原则上@Autowired注入规则为“byType”(通过类型注入)
原则上@Resource注入规则为“byName”(通过名称注入)这里的名称就是对象的id3.匹配规则不同
@Auotowired是先检查类型,如果有类型匹配直接匹配,只通过类型不能匹配,在通过id;
@Resource是先匹配id,如果有id匹配,直接成功;如果没有id匹配,在进行类型匹配;
2、调用Spring Security安全认证方法
关键代码
// 用户名、密码构建UsernamePasswordAuthenticationToken对象
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
AuthenticationContextHolder.setContext(authenticationToken);
// 调用认证方法,验证用户名和密码
Authentication authentication = authenticationManager.authenticate(authenticationToken);
《将ProviderManager对象做为authenticationManager的bean对象流程源码分析图》
说明
验证用户名和密码,通过调用认证方法后,通过上图所示最终是调用了ProviderManager.authenticate()方法
给大家的福利
零基础入门
对于从来没有接触过网络安全的同学,我们帮你准备了详细的学习成长路线图。可以说是最科学最系统的学习路线,大家跟着这个大的方向学习准没问题。
同时每个成长路线对应的板块都有配套的视频提供:
因篇幅有限,仅展示部分资料
网络安全面试题
绿盟护网行动
还有大家最喜欢的黑客技术
网络安全源码合集+工具包
所有资料共282G,朋友们如果有需要全套《网络安全入门+黑客进阶学习资源包》,可以扫描下方二维码领取(如遇扫码问题,可以在评论区留言领取哦)~
需要体系化学习资料的朋友,可以加我V获取:vip204888 (备注网络安全)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!