您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“常見(jiàn)的SpringSecurity問(wèn)題有哪些”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
我們已經(jīng)知道SpringSecurity的DefaultLoginPageGeneratingFilter會(huì)我們默認(rèn)生成登錄頁(yè),這個(gè)路徑是login。
但是我們處理登錄的路徑是啥呢?
我們可以看到登錄頁(yè)面也是login。
這就其了怪了,為什么同樣的路徑產(chǎn)生了不同的效果?
因?yàn)椋篐TTP method的不同,登錄頁(yè)面是GET請(qǐng)求,登錄操作是POST請(qǐng)求。
操作就是這么騷,讓無(wú)數(shù)人閃了腰。
所以,當(dāng)你做前后端分離項(xiàng)目,前端使用get('/login',optioin)發(fā)現(xiàn)是404,不要奇怪,不要流淚,改成post也許就好了。
這么騷的操作是如何實(shí)現(xiàn)的呢?
答案在UsernamePasswordAuthenticationFilter:
我們可以看到,UsernamePasswordAuthenticationFilter只匹配post的login,也可以看到為什么通過(guò)UsernamePasswordAuthenticationFilter認(rèn)證參數(shù)必須是username和password了。
其實(shí),操作都是在它的父類AbstractAuthenticationProcessingFilter中完成,既然是Filter肯定看doFilter方法,調(diào)用了requiresAuthentication。
2次login:
首先是(login,get)UsernamePasswordAuthenticationFilter沒(méi)有處理直接跳過(guò)了,如果是需要授權(quán)的url,后面到了ExceptionTranslationFilter,因?yàn)樾枰J(rèn)證和授權(quán),于是被重定向到了登錄頁(yè)面。
然后是(login,post)匹配上了,通過(guò)UsernamePasswordAuthenticationFilter完成了認(rèn)證操作。
當(dāng)然上面參數(shù)都是可以配置的,例如,登錄頁(yè)面url、處理登錄的url、用戶名參數(shù)、密碼參數(shù)、沒(méi)有認(rèn)證咋處理,認(rèn)證成功咋處理:
@Override protected void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage("/login")//登錄頁(yè)面 .loginProcessingUrl("/do-login")//處理登錄邏輯 .passwordParameter("username")//用戶名參數(shù) .passwordParameter("password")//密碼參數(shù) // 三個(gè)配置一個(gè)就可以了 .defaultSuccessUrl("/loginsucess").successForwardUrl("/sucess").successHandler(sucessHandler) // 三個(gè)配置一個(gè)就可以了 .failureForwardUrl("/fail").failureUrl("/failure").failureHandler(loginAuthenticationFailureHandler) .permitAll(); }
defaultSuccessUrl和successForwardUrl,最好使用defaultSuccessUrl,可以重定向到來(lái)登錄頁(yè)面之前的url,defaultSuccessUrl還接收一個(gè)boolean參數(shù),如果設(shè)置為true,就和successForwardUrl等價(jià)。
如果,想要了解login和UsernamePasswordAuthenticationFilter到底是怎樣聯(lián)系起來(lái)的,還得看http.formLogin():
public FormLoginConfigurer<HttpSecurity> formLogin() throws Exception { return getOrApply(new FormLoginConfigurer<>()); }
FormLoginConfigurer看名字我們就知道是一個(gè)Configurer配置類,這個(gè)類前面的文章已經(jīng)介紹了,可以看一下,也可以簡(jiǎn)單看一下后面的重要SecurityBuilder提示:
有興趣可以自己看一下這個(gè)類,這里就不詳細(xì)展開(kāi)了。
如果出現(xiàn)如上圖所示的無(wú)限循環(huán)問(wèn)題,那么多半有類似下面的配置:
@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(); }
了解了前面的登錄流程,理解這個(gè)無(wú)限循環(huán)就容易多了,就是因?yàn)閘ogin不需要被認(rèn)證,但是login需要被授權(quán),于是ExceptionTranslationFilter到被定向到默認(rèn)的登錄頁(yè)面login,然后進(jìn)入無(wú)限套娃模式。
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests().antMatchers("/index.html").permitAll().anyRequest().authenticated(); http.formLogin(); }
關(guān)于授權(quán)主要看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(); }
自己測(cè)試很多時(shí)候會(huì)把csrf禁用,否則,使用post,但是參數(shù)在url中這種請(qǐng)求就會(huì)被攔截。
protected void configure(HttpSecurity http) throws Exception { http.cors().and().csrf().disable(); }
WebSecurity是一個(gè)SecurityBuilder<Filter>,所以它的主要職責(zé)之一就是創(chuàng)建Filter,重點(diǎn)關(guān)注它的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; } }
很標(biāo)準(zhǔn)的模板方法模式。
正真執(zhí)行構(gòu)建的邏輯在performBuild方法中,這個(gè)方法在WebSecurity創(chuàng)建了FilterChainProxy,在HttpSecurity中創(chuàng)建了DefaultSecurityFilterChain。
前面已經(jīng)分析了,HttpSecurity的目的就一個(gè)創(chuàng)建DefaultSecurityFilterChain,注意它的performBuild方法。
“常見(jiàn)的SpringSecurity問(wèn)題有哪些”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。