歡迎閱讀 Spring Security 實戰乾貨 系列文章 。最近有開發小夥伴提了一個有趣的問題。他正在作一個項目,涉及兩種風格,一種是給小程序出接口,安全上使用無狀態的JWT Token;另外一種是管理後臺使用的是Freemarker,也就是先後端不分離的Session機制。用Spring Security該怎麼辦?html
咱們能夠經過屢次繼承WebSecurityConfigurerAdapter構建多個HttpSecurity
。HttpSecurity
對象會告訴咱們如何驗證用戶的身份,如何進行訪問控制,採起的何種策略等等。java
若是你看過以前的教程,咱們是這麼配置的:web
/** * 單策略配置 * * @author felord.cn * @see org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration * @since 14 :58 2019/10/15 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true, securedEnabled = true)
@EnableWebSecurity
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class CustomSpringBootWebSecurityConfiguration {
/** * The type Default configurer adapter. */
@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER)
static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
}
@Override
public void configure(WebSecurity web) {
super.configure(web);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 配置 httpSecurity
}
}
}
複製代碼
上面的配置了一個HttpSecurity
,咱們如法炮製再增長一個WebSecurityConfigurerAdapter
的子類來配置另外一個HttpSecurity
。伴隨而來的還有很多的問題要解決。spring
咱們配置了兩個HttpSecurity
以後,程序如何讓小程序接口和後臺接口走對應的HttpSecurity
?小程序
HttpSecurity.antMatcher(String antPattern)
能夠提供過濾機制。好比咱們配置:後端
@Override
protected void configure(HttpSecurity http) throws Exception {
// 配置 httpSecurity
http.antMatcher("/admin/v1");
}
複製代碼
那麼該HttpSecurity
將只提供給以/admin/v1
開頭的全部URL。這要求咱們針對不一樣的客戶端指定統一的URL前綴。安全
觸類旁通只要
HttpSecurity
提供的功能均可以進行個性化定製。好比登陸方式,角色體系等。session
咱們能夠經過在WebSecurityConfigurerAdapter
實現上使用@Order
註解來指定優先級,數值越大優先級越低,沒有@Order
註解將優先級最低。app
不少狀況下咱們但願普通用戶和管理用戶徹底隔離,咱們就須要多個UserDetailsService
,你能夠在下面的方法中對AuthenticationManagerBuilder
進行具體的設置來配置UserDetailsService
,同時也能夠配置不一樣的密碼策略。ide
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setUserDetailsService(new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 自行實現
return null ;
}
});
// 也能夠設計特定的密碼策略
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder);
auth.authenticationProvider(daoAuthenticationProvider);
}
複製代碼
上面的幾個問題解決以後,咱們基本上掌握了在一個應用中執行多種安全策略。配置模板以下:
/** * 多個策略配置 * * @author felord.cn * @see org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration * @since 14 :58 2019/10/15 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true, securedEnabled = true)
@EnableWebSecurity
@ConditionalOnClass(WebSecurityConfigurerAdapter.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public class CustomSpringBootWebSecurityConfiguration {
/** * 後臺接口安全策略. 默認配置 */
@Configuration
@Order(1)
static class AdminConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
//用戶詳情服務個性化
daoAuthenticationProvider.setUserDetailsService(new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 自行實現
return null;
}
});
// 也能夠設計特定的密碼策略
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder);
auth.authenticationProvider(daoAuthenticationProvider);
}
@Override
public void configure(WebSecurity web) {
super.configure(web);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 根據需求自行定製
http.antMatcher("/admin/v1")
.sessionManagement(Customizer.withDefaults())
.formLogin(Customizer.withDefaults());
}
}
/** * app接口安全策略. 沒有{@link Order}註解優先級比上面低 */
@Configuration
static class AppConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
//用戶詳情服務個性化
daoAuthenticationProvider.setUserDetailsService(new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 自行實現
return null;
}
});
// 也能夠設計特定的密碼策略
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder);
auth.authenticationProvider(daoAuthenticationProvider);
}
@Override
public void configure(WebSecurity web) {
super.configure(web);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 根據需求自行定製
http.antMatcher("/app/v1")
.sessionManagement(Customizer.withDefaults())
.formLogin(Customizer.withDefaults());
}
}
}
複製代碼
今天咱們解決了如何針對不一樣類型接口採起不一樣的安全策略的方法,但願對你有用,若是你有什麼問題能夠留言。多多關注:碼農小胖哥,更多幹貨奉上。
關注公衆號:Felordcn獲取更多資訊