扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
本篇内容介绍了“常见的SpringSecurity问题有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
创新互联公司云计算的互联网服务提供商,拥有超过13年的服务器租用、移动服务器托管、云服务器、虚拟空间、网站系统开发经验,已先后获得国家工业和信息化部颁发的互联网数据中心业务许可证。专业提供云主机、虚拟空间、国际域名空间、VPS主机、云服务器、香港云服务器、免备案服务器等。
我们已经知道SpringSecurity的DefaultLoginPageGeneratingFilter会我们默认生成登录页,这个路径是login。
但是我们处理登录的路径是啥呢?
我们可以看到登录页面也是login。
这就其了怪了,为什么同样的路径产生了不同的效果?
因为:HTTP method的不同,登录页面是GET请求,登录操作是POST请求。
操作就是这么骚,让无数人闪了腰。
所以,当你做前后端分离项目,前端使用get('/login',optioin)发现是404,不要奇怪,不要流泪,改成post也许就好了。
这么骚的操作是如何实现的呢?
答案在UsernamePasswordAuthenticationFilter:
我们可以看到,UsernamePasswordAuthenticationFilter只匹配post的login,也可以看到为什么通过UsernamePasswordAuthenticationFilter认证参数必须是username和password了。
其实,操作都是在它的父类AbstractAuthenticationProcessingFilter中完成,既然是Filter肯定看doFilter方法,调用了requiresAuthentication。
2次login:
首先是(login,get)UsernamePasswordAuthenticationFilter没有处理直接跳过了,如果是需要授权的url,后面到了ExceptionTranslationFilter,因为需要认证和授权,于是被重定向到了登录页面。
然后是(login,post)匹配上了,通过UsernamePasswordAuthenticationFilter完成了认证操作。
当然上面参数都是可以配置的,例如,登录页面url、处理登录的url、用户名参数、密码参数、没有认证咋处理,认证成功咋处理:
@Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/login")//登录页面 .loginProcessingUrl("/do-login")//处理登录逻辑 .passwordParameter("username")//用户名参数 .passwordParameter("password")//密码参数 // 三个配置一个就可以了 .defaultSuccessUrl("/loginsucess").successForwardUrl("/sucess").successHandler(sucessHandler) // 三个配置一个就可以了 .failureForwardUrl("/fail").failureUrl("/failure").failureHandler(loginAuthenticationFailureHandler) .permitAll(); }
defaultSuccessUrl和successForwardUrl,最好使用defaultSuccessUrl,可以重定向到来登录页面之前的url,defaultSuccessUrl还接收一个boolean参数,如果设置为true,就和successForwardUrl等价。
如果,想要了解login和UsernamePasswordAuthenticationFilter到底是怎样联系起来的,还得看http.formLogin():
public FormLoginConfigurerformLogin() throws Exception { return getOrApply(new FormLoginConfigurer<>()); }
FormLoginConfigurer看名字我们就知道是一个Configurer配置类,这个类前面的文章已经介绍了,可以看一下,也可以简单看一下后面的重要SecurityBuilder提示:
有兴趣可以自己看一下这个类,这里就不详细展开了。
如果出现如上图所示的无限循环问题,那么多半有类似下面的配置:
@Override public void configure(WebSecurity web) { web.ignoring().antMatchers( "/login" ); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/index.html").permitAll().anyRequest().authenticated(); http.formLogin(); }
了解了前面的登录流程,理解这个无限循环就容易多了,就是因为login不需要被认证,但是login需要被授权,于是ExceptionTranslationFilter到被定向到默认的登录页面login,然后进入无限套娃模式。
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/index.html").permitAll().anyRequest().authenticated(); http.formLogin(); }
关于授权主要看http.authorizeRequests()方法:
public ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry authorizeRequests() throws Exception { ApplicationContext context = getContext(); return getOrApply(new ExpressionUrlAuthorizationConfigurer<>(context)).getRegistry(); }
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class CorsConfig implements WebMvcConfigurer { private CorsConfiguration buildConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.addAllowedOrigin("*"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.addExposedHeader("Authorization"); return corsConfiguration; } @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", buildConfig()); return new CorsFilter(source); } @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") // .allowCredentials(true) .allowedMethods("GET", "POST", "DELETE", "PUT") .maxAge(3600); } }
除了上面的配置,还需要:
protected void configure(HttpSecurity http) throws Exception { http.cors(); }
自己测试很多时候会把csrf禁用,否则,使用post,但是参数在url中这种请求就会被拦截。
protected void configure(HttpSecurity http) throws Exception { http.cors().and().csrf().disable(); }
WebSecurity是一个SecurityBuilder
@Override protected final O doBuild() throws Exception { synchronized (this.configurers) { this.buildState = BuildState.INITIALIZING; beforeInit(); init(); this.buildState = BuildState.CONFIGURING; beforeConfigure(); configure(); this.buildState = BuildState.BUILDING; O result = performBuild(); this.buildState = BuildState.BUILT; return result; } }
很标准的模板方法模式。
正真执行构建的逻辑在performBuild方法中,这个方法在WebSecurity创建了FilterChainProxy,在HttpSecurity中创建了DefaultSecurityFilterChain。
前面已经分析了,HttpSecurity的目的就一个创建DefaultSecurityFilterChain,注意它的performBuild方法。
“常见的SpringSecurity问题有哪些”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注创新互联网站,小编将为大家输出更多高质量的实用文章!
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流