本篇內容介紹了“常見的SpringSecurity問題有哪些”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
我們已經知道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 FormLoginConfigurer<HttpSecurity> formLogin() 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<HttpSecurity>.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<Filter>,所以它的主要職責之一就是創建Filter,重點關注它的build方法,是繼承了AbstractSecurityBuilder的build,具體邏輯在AbstractConfiguredSecurityBuilder的doBuild方法中。
@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問題有哪些”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。