日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
一套系統(tǒng)多套用戶安全體系該怎么辦

路徑攔截策略

在Spring Security中當(dāng)然是按照不同的請(qǐng)求路徑規(guī)則定義專門的過濾器鏈,你可以通過三種方式來實(shí)現(xiàn)路徑攔截。然后按照策略定義過濾器鏈即可:

成都創(chuàng)新互聯(lián)主要業(yè)務(wù)有網(wǎng)站營銷策劃、成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、微信公眾號(hào)開發(fā)、小程序定制開發(fā)、H5開發(fā)、程序開發(fā)等業(yè)務(wù)。一次合作終身朋友,是我們奉行的宗旨;我們不僅僅把客戶當(dāng)客戶,還把客戶視為我們的合作伙伴,在開展業(yè)務(wù)的過程中,公司還積累了豐富的行業(yè)經(jīng)驗(yàn)、全網(wǎng)整合營銷推廣資源和合作伙伴關(guān)系資源,并逐漸建立起規(guī)范的客戶服務(wù)和保障體系。 

@Bean
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
SecurityFilterChain systemSecurityFilterChain(HttpSecurity http) throws Exception {
// 省略
}

這三種策略介紹如下。

按照正則過濾

你可以通過HttpSecurity提供的過濾器過濾URI,例如攔截請(qǐng)求中在query參數(shù)而且包含id的URI:

 http.regexMatcher("/(\\\\?|\\\\&)\" + id + \"=([^\\\\&]+)/")   

這種常用來匹配一些帶參數(shù)的URL。

按照Ant規(guī)則過濾

這種是我們常見的方式,例如攔截/system開頭的所有路徑:

 http.antMatcher("/system/**")

關(guān)于這種方式這里不再贅述,詳細(xì)可以通過Ant規(guī)則詳解這一篇來了解。

按照RequestMatcher過濾

一些復(fù)雜的組合可以通過定義RequestMatcher接口來組合,例如這種復(fù)雜的規(guī)則:

RequestMatcher requestMatcher = new OrRequestMatcher(
new AntPathRequestMatcher(
providerSettings.getTokenEndpoint(),
HttpMethod.POST.name()),
new AntPathRequestMatcher(
providerSettings.getTokenIntrospectionEndpoint(),
HttpMethod.POST.name()),
new AntPathRequestMatcher(
providerSettings.getTokenRevocationEndpoint(),
HttpMethod.POST.name()));

http.requestMatcher(requestMatcher)

滿足三個(gè)路徑中的一個(gè)就行,這種組合方式能夠?qū)崿F(xiàn)最復(fù)雜的攔截策略。

配置隔離的一些要點(diǎn)

這里還要注意配置之間的隔離。

Session會(huì)話

默認(rèn)情況下的Session依賴于cookie中設(shè)定的jsessionid, 如果你使用會(huì)話模式,必須隔離多個(gè)過濾器鏈的會(huì)話存儲(chǔ),這樣能夠?qū)崿F(xiàn)一個(gè)多個(gè)過濾器在同一個(gè)會(huì)話下不同的登錄狀態(tài),否則它們共享配置就會(huì)發(fā)生錯(cuò)亂。

這是因?yàn)樵谝粋€(gè)會(huì)話下,默認(rèn)的屬性Key是SPRING_SECURITY_CONTEXT,當(dāng)在同一個(gè)會(huì)話下(同一個(gè)瀏覽器不同的tab頁)獲取當(dāng)前上下文都是這樣的:

// 默認(rèn) SPRING_SECURITY_CONTEXT
Object contextFromSession = httpSession.getAttribute(this.springSecurityContextKey);

這樣登錄一個(gè),其它都認(rèn)為是登錄狀態(tài),這顯然不符合預(yù)期。你需要在不同的過濾器中定義不同的會(huì)話屬性Key。

final String ID_SERVER_SYSTEM_SECURITY_CONTEXT_KEY ="SOME_UNIQUE_KEY"       
HttpSessionSecurityContextRepository hs = new HttpSessionSecurityContextRepository();
hs.setSpringSecurityContextKey(ID_SERVER_SYSTEM_SECURITY_CONTEXT_KEY);

http.securityContext().securityContextRepository(hs)

無狀態(tài)Token

無狀態(tài)Token相對(duì)簡(jiǎn)單一些,前端根據(jù)路徑分開存儲(chǔ)即可,而且Token中應(yīng)該包含校驗(yàn)過濾器鏈的信息以方便后端校驗(yàn),避免Token混用。

UserDetailsService

如果你的不同端的用戶是獨(dú)立的,你需要實(shí)現(xiàn)不同的UserDetailsService,但是存在多個(gè)UserDetailsService的話,

一定不要將它們直接注冊(cè)到Spring IoC中!

一定不要將它們直接注冊(cè)到Spring IoC中!

一定不要將它們直接注冊(cè)到Spring IoC中!

如果你一定要注冊(cè)到Spring IoC,你需要定義獨(dú)立的接口,就像這樣:

@FunctionalInterface
public interface OAuth2UserDetailsService {

UserDetails loadOAuth2UserByUsername(String username) throws UsernameNotFoundException;
}

然后實(shí)現(xiàn)該接口再注入Spring IoC,每個(gè)過濾器鏈配置的時(shí)候就可以這樣寫:

 @Bean
@Order(Ordered.HIGHEST_PRECEDENCE + 2)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http,
OAuth2UserDetailsService oAuth2UserDetailsService) throws Exception {
http.userDetailsService(oAuth2UserDetailsService::loadOAuth2UserByUsername)
}

但是Spring IoC中必須有一個(gè)UserDetailsService,你得這樣寫:

@Bean
UserDetailsService notFoundUserDetailsService() {
return username -> {
throw new UsernameNotFoundException("用戶未找到");
};
}

為啥不可用,因?yàn)樽⑷隨pring IoC的UserDetailsService是一個(gè)兜底的實(shí)現(xiàn),如果你只有一個(gè)實(shí)現(xiàn),放入Spring IoC無可厚非,如果你想讓多個(gè)各自走各自的就必須這樣寫最安全,不然還有一個(gè)默認(rèn)的InMemoryUserDetailsManager也會(huì)生效成為兜底的。

其它

其它配置按照各自的配置就行了,目前我還沒有發(fā)現(xiàn)有沖突的地方。上面所講的東西,在Id Server授權(quán)服務(wù)器中就是這樣實(shí)現(xiàn)授權(quán)服務(wù)器過濾、后臺(tái)管理用戶和前臺(tái)授權(quán)用戶三者之間隔離的:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class IdServerSecurityConfiguration {

private static final String CUSTOM_CONSENT_PAGE_URI = "/oauth2/consent";
private static final String SYSTEM_ANT_PATH = "/system/**";
/**
* The constant ID_SERVER_SYSTEM_SECURITY_CONTEXT_KEY.
*/
public static final String ID_SERVER_SYSTEM_SECURITY_CONTEXT_KEY = "ID_SERVER_SYSTEM_SECURITY_CONTEXT";

/**
* 授權(quán)服務(wù)器配置
*
* @author felord.cn
* @since 1.0.0
*/
@Configuration(proxyBeanMethods = false)
public static class AuthorizationServerConfiguration {

/**
* Authorization server 集成 優(yōu)先級(jí)要高一些
*
* @param http the http
* @return the security filter chain
* @throws Exception the exception
* @since 1.0.0
*/
@Bean("authorizationServerSecurityFilterChain")
@Order(Ordered.HIGHEST_PRECEDENCE)
SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {
OAuth2AuthorizationServerConfigurer authorizationServerConfigurer =
new OAuth2AuthorizationServerConfigurer<>();
// 把自定義的授權(quán)確認(rèn)URI加入配置
authorizationServerConfigurer.authorizationEndpoint(authorizationEndpointConfigurer ->
authorizationEndpointConfigurer.consentPage(CUSTOM_CONSENT_PAGE_URI));

RequestMatcher authorizationServerEndpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();

// 攔截 授權(quán)服務(wù)器相關(guān)的請(qǐng)求端點(diǎn)
http.requestMatcher(authorizationServerEndpointsMatcher)
.authorizeRequests().anyRequest().authenticated()
.and()
// 忽略掉相關(guān)端點(diǎn)的csrf
.csrf(csrf -> csrf
.ignoringRequestMatchers(authorizationServerEndpointsMatcher))
.formLogin()
.and()
// 應(yīng)用 授權(quán)服務(wù)器的配置
.apply(authorizationServerConfigurer);
return http.build();
}

/**
* 配置 OAuth2.0 provider元信息
*
* @param port the port
* @return the provider settings
* @since 1.0.0
*/
@Bean
public ProviderSettings providerSettings(@Value("${server.port}") Integer port) {
//TODO 配置化 生產(chǎn)應(yīng)該使用域名
return ProviderSettings.builder().issuer("http://localhost:" + port).build();
}
}

/**
* 后臺(tái)安全配置.
*
* @author felord.cn
* @since 1.0.0
*/
@Configuration(proxyBeanMethods = false)
public static class SystemSecurityConfiguration {

/**
* 管理后臺(tái)以{@code /system}開頭
*
* @param http the http
* @return the security filter chain
* @throws Exception the exception
* @see AuthorizationServerConfiguration
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
SecurityFilterChain systemSecurityFilterChain(HttpSecurity http, UserInfoService userInfoService) throws Exception {
SimpleAuthenticationEntryPoint authenticationEntryPoint = new SimpleAuthenticationEntryPoint();
AuthenticationEntryPointFailureHandler authenticationFailureHandler = new AuthenticationEntryPointFailureHandler(authenticationEntryPoint);
HttpSessionSecurityContextRepository securityContextRepository = new HttpSessionSecurityContextRepository();
securityContextRepository.setSpringSecurityContextKey(ID_SERVER_SYSTEM_SECURITY_CONTEXT_KEY);
http.antMatcher(SYSTEM_ANT_PATH).csrf().disable()
.headers().frameOptions().sameOrigin()
.and()
.securityContext().securityContextRepository(securityContextRepository)
.and()
.authorizeRequests().anyRequest().authenticated()
/* .and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)*/
.and()
.userDetailsService(userInfoService::findByUsername)
.formLogin().loginPage("/system/login").loginProcessingUrl("/system/login")
.successHandler(new RedirectLoginAuthenticationSuccessHandler("/system"))
.failureHandler(authenticationFailureHandler).permitAll();
return http.build();
}

}

/**
* 普通用戶訪問安全配置.
*
* @author felord.cn
* @since 1.0.0
*/
@Configuration(proxyBeanMethods = false)
public static class OAuth2SecurityConfiguration {

/**
* Default security filter chain security filter chain.
*
* @param http the http
* @param oAuth2UserDetailsService the oauth2 user details service
* @param securityFilterChain the security filter chain
* @return the security filter chain
* @throws Exception the exception
*/
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE + 2)
SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http,
OAuth2UserDetailsService oAuth2UserDetailsService,
@Qualifier("authorizationServerSecurityFilterChain") SecurityFilterChain securityFilterChain) throws Exception {
DefaultSecurityFilterChain authorizationServerFilterChain = (DefaultSecurityFilterChain) securityFilterChain;
SimpleAuthenticationEntryPoint authenticationEntryPoint = new SimpleAuthenticationEntryPoint();
AuthenticationEntryPointFailureHandler authenticationFailureHandler = new AuthenticationEntryPointFailureHandler(authenticationEntryPoint);
http.requestMatcher(new AndRequestMatcher(
new NegatedRequestMatcher(new AntPathRequestMatcher(SYSTEM_ANT_PATH)),
new NegatedRequestMatcher(authorizationServerFilterChain.getRequestMatcher())
)).authorizeRequests(authorizeRequests ->
authorizeRequests
.anyRequest().authenticated()
).csrf().disable()
.userDetailsService(oAuth2UserDetailsService::loadOAuth2UserByUsername)
.formLogin().loginPage("/login")
.successHandler(new RedirectLoginAuthenticationSuccessHandler())
.failureHandler(authenticationFailureHandler).permitAll()
.and()
.oauth2ResourceServer().jwt();
return http.build();
}

}
}

你可以通過https://github.com/NotFound403/id-server下載源碼進(jìn)行改造學(xué)習(xí),歡迎Star。


文章標(biāo)題:一套系統(tǒng)多套用戶安全體系該怎么辦
網(wǎng)站路徑:http://www.dlmjj.cn/article/djcggse.html