spring security 自定义登录以及配置跨域问题
- springboot低版本升级高版本跨域配置稍微有些不一样,见下面代码的corsConfigurationSource()方法。
- 此处登录即支持客户端传json格式参数,也支持springSecurity默认支持的formData格式的参数(username和password)
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//登录成功处理逻辑
@Autowired
CustomizeAuthenticationSuccessHandler authenticationSuccessHandler;
//登录失败处理逻辑
@Autowired
CustomizeAuthenticationFailureHandler authenticationFailureHandler;
//权限拒绝处理逻辑
@Autowired
CustomizeAccessDeniedHandler accessDeniedHandler;
//匿名用户访问无权限资源时的异常
@Autowired
CustomizeAuthenticationEntryPoint authenticationEntryPoint;
//会话失效(账号被挤下线)处理逻辑
@Autowired
CustomizeSessionInformationExpiredStrategy sessionInformationExpiredStrategy;
//登出成功处理逻辑
@Autowired
CustomizeLogoutSuccessHandler logoutSuccessHandler;
//访问决策管理器
@Autowired
CustomizeAccessDecisionManager accessDecisionManager;
//实现权限拦截
@Autowired
CustomizeFilterInvocationSecurityMetadataSource securityMetadataSource;
@Autowired
private CustomizeAbstractSecurityInterceptor securityInterceptor;
@Autowired
@Qualifier("userDetailsServiceImpl")
private UserDetailsService userDetailsService;
/**
* 密码加密方式
* @return
*/
@Bean
public BCryptPasswordEncoder passwordEncoder() {
// 设置默认的加密方式(强hash方式加密)
return new BCryptPasswordEncoder();
}
/**
* 自定义用户名密码鉴定,支持json格式传入的用户名密码
* {@link WebSecurityConfig#configure(HttpSecurity)} 配置方法里用到这个bean
* @throws Exception
*/
@Bean
CustomizeUsernamePasswordAuthenticationFilter customizeUsernamePasswordAuthenticationFilter() throws Exception {
CustomizeUsernamePasswordAuthenticationFilter filter = new CustomizeUsernamePasswordAuthenticationFilter();
// 登录成功以及登录失败的处理器由下面configure()方法里移动到这里,否则不生效(不生效原因是因为这个自定义的过滤器会先于默认的过滤器执行)
filter.setAuthenticationSuccessHandler(authenticationSuccessHandler);
filter.setAuthenticationFailureHandler(authenticationFailureHandler);
filter.setAuthenticationManager(authenticationManagerBean());
return filter;
}
// 配置跨域访问资源
private CorsConfigurationSource corsConfigurationSource() {
CorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOriginPattern("*"); //spring boot2.4.0版本之后使用这个配置
// corsConfiguration.addAllowedOrigin("*"); //spring boot2.4.0版本之前使用这个 同源配置,*表示任何请求都视为同源,若需指定ip和端口可以改为如“localhost:8080”,多个以“,”分隔;
corsConfiguration.addAllowedHeader("*");//header,允许哪些header,本案中使用的是token,此处可将*替换为token;
corsConfiguration.addAllowedMethod("*"); //允许的请求方法,PSOT、GET等
((UrlBasedCorsConfigurationSource) source).registerCorsConfiguration("/**",corsConfiguration); //配置允许跨域访问的url
return source;
}
/**
* 配置自己系统实现的用户认证
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(corsConfigurationSource()) // 配置跨域问题
.and()
.csrf().disable();
http.authorizeRequests()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O o) {
o.setAccessDecisionManager(accessDecisionManager);//决策管理器
o.setSecurityMetadataSource(securityMetadataSource);//安全元数据源
return o;
}
})
//登出
.and()
.logout()
.permitAll()//允许所有用户
.logoutSuccessHandler(logoutSuccessHandler)//登出成功处理逻辑
.deleteCookies("JSESSIONID")//登出之后删除cookie
//登入
.and()
.formLogin()
.permitAll()//允许所有用户
/** 下面配置了自定义的用户名密码校验,所以此处两个处理器不生效了 {@link WebSecurityConfig#customizeUsernamePasswordAuthenticationFilter()} */
// .successHandler(authenticationSuccessHandler)//登录成功处理逻辑
// .failureHandler(authenticationFailureHandler)//登录失败处理逻辑
//异常处理(权限拒绝、登录失效等)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)//权限拒绝处理逻辑
.authenticationEntryPoint(authenticationEntryPoint)//匿名用户访问无权限资源时的异常处理
//会话管理
.and()
.sessionManagement()
.maximumSessions(1)//同一账号同时登录最大用户数
.expiredSessionStrategy(sessionInformationExpiredStrategy);//会话失效(账号被挤下线)处理逻辑
http.addFilterBefore(securityInterceptor, FilterSecurityInterceptor.class);
http.addFilterAt(customizeUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}