适用于session方式的登录,不适用于jwt token方式的登录。因为jwt token方式的话session就没什么事儿了 (此处为了防止小白不懂原理盲目抄)。
有这样一个需求,一个账号只能在一个客户端浏览器上登录,如果同样的账号在别的客户端浏览器上登录的话,之前的登录需要被踢下去。这个需求看似很简单,而且默认情况下使用Spring Security配置也挺简单,如下配置即可:
-
@Override
-
protected
void
configure
(HttpSecurity http)
throws Exception {
-
http
-
-
...
//此处忽略若干行配置
-
-
.sessionManagement()
-
.maximumSessions(
1);
-
}
这个配置在默认formLogin状态下生效,但如果使用自定义过滤器接管登录过程的话就会失效,如这样:
-
@Override
-
protected
void
configure
(HttpSecurity http)
throws Exception {
-
http
-
...
//此处忽略若干行配置
-
// 添加自己的登录过滤器
-
.addFilterBefore(adminLoginFilter(), UsernamePasswordAuthenticationFilter.class)
-
// 因为adminLoginFilter接管了默认formLogin的工作,所以下面的session配置失效了
-
.sessionManagement()
-
.maximumSessions(
1);
-
}
这时我们需要手动配置session了,先看看官网是怎么说的 官网说明 这是官网的一段话
If you are using a customized authentication filter for form-based login, then you have to configure concurrent session control support explicitly.
官网也提供了具体配置方法
-
<http>
-
<custom-filter position=
"CONCURRENT_SESSION_FILTER" ref=
"concurrencyFilter" />
-
<custom-filter position=
"FORM_LOGIN_FILTER" ref=
"myAuthFilter" />
-
-
<session-management session-authentication-strategy-ref=
"sas"/>
-
</http>
-
-
<beans:bean id=
"redirectSessionInformationExpiredStrategy"
-
class=
"org.springframework.security.web.session.SimpleRedirectSessionInformationExpiredStrategy">
-
<beans:constructor-arg name=
"invalidSessionUrl" value=
"/session-expired.htm" />
-
</beans:bean>
-
-
<beans:bean id=
"concurrencyFilter"
-
class=
"org.springframework.security.web.session.ConcurrentSessionFilter">
-
<beans:constructor-arg name=
"sessionRegistry" ref=
"sessionRegistry" />
-
<beans:constructor-arg name=
"sessionInformationExpiredStrategy" ref=
"redirectSessionInformationExpiredStrategy" />
-
</beans:bean>
-
-
<beans:bean id=
"myAuthFilter" class=
-
"org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
-
<beans:property name=
"sessionAuthenticationStrategy" ref=
"sas" />
-
<beans:property name=
"authenticationManager" ref=
"authenticationManager" />
-
</beans:bean>
-
-
<beans:bean id=
"sas" class=
"org.springframework.security.web.authentication.session.CompositeSessionAuthenticationStrategy">
-
<beans:constructor-arg>
-
<beans:list>
-
<beans:bean class=
"org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy">
-
<beans:constructor-arg ref=
"sessionRegistry"/>
-
<beans:property name=
"maximumSessions" value=
"1" />
-
<beans:property name=
"exceptionIfMaximumExceeded" value=
"true" />
-
</beans:bean>
-
<beans:bean class=
"org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy">
-
</beans:bean>
-
<beans:bean class=
"org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy">
-
<beans:constructor-arg ref=
"sessionRegistry"/>
-
</beans:bean>
-
</beans:list>
-
</beans:constructor-arg>
-
</beans:bean>
-
-
<beans:bean id=
"sessionRegistry"
-
class=
"org.springframework.security.core.session.SessionRegistryImpl" />
官网提供的是xml配置方法,现在应该是比较少用了,所以我们得在自己项目中使用代码配置,具体流程:
第一步 定义一个sessionRegistry bean
-
@Bean
-
public SessionRegistry
sessionRegistry
(){
-
return
new
SessionRegistryImpl();
-
}
第二步 定义几个Session Strategy bean,其中在ConcurrentSessionControlAuthenticationStrategy配置账号的最大同时登录数
-
@Bean
-
public ConcurrentSessionControlAuthenticationStrategy
controlAuthenticationStrategy
(SessionRegistry sessionRegistry){
-
ConcurrentSessionControlAuthenticationStrategy
strategy
=
new
ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
-
strategy.setMaximumSessions(
1);
// 这里配置一个账号最大登录数
-
return strategy;
-
}
-
-
@Bean
-
public SessionFixationProtectionStrategy
sessionFixationProtectionStrategy
(){
-
return
new
SessionFixationProtectionStrategy();
-
}
-
-
@Bean
-
public RegisterSessionAuthenticationStrategy
registerSessionAuthenticationStrategy
(SessionRegistry sessionRegistry){
-
return
new
RegisterSessionAuthenticationStrategy(sessionRegistry);
-
}
第三步 定义CompositeSessionAuthenticationStrategy bean,他接受的是List集合,也就是其他Session Strategy的集合
-
@Bean
-
public CompositeSessionAuthenticationStrategy
sessionAuthenticationStrategy
(List<SessionAuthenticationStrategy> authenticationStrategies){
-
return
new
CompositeSessionAuthenticationStrategy(authenticationStrategies);
-
}
第四步 定义ConcurrentSessionFilter bean
-
@Bean
-
public ConcurrentSessionFilter
concurrentSessionFilter
(SessionRegistry sessionRegistry){
-
return
new
ConcurrentSessionFilter(sessionRegistry);
-
}
第五步 在自己的自定义登录filter里面设置session strategy
-
public AdminLoginFilter
adminLoginFilter
(CompositeSessionAuthenticationStrategy strategy)
throws Exception {
-
AdminLoginFilter
adminLoginFilter
=
new
AdminLoginFilter();
-
... 省略若干行配置
-
adminLoginFilter.setSessionAuthenticationStrategy(strategy);
-
return adminLoginFilter;
-
}
第六步 在configure(HttpSecurity http)里面配置session
-
@Override
-
protected
void
configure
(HttpSecurity http)
throws Exception {
-
List<SessionAuthenticationStrategy> authenticationStrategies = Arrays.asList(
-
controlAuthenticationStrategy(sessionRegistry()),
-
sessionFixationProtectionStrategy(),
-
registerSessionAuthenticationStrategy(sessionRegistry())
-
);
-
-
http
-
...
//此处忽略若干行配置
-
.addFilterBefore(concurrentSessionFilter(sessionRegistry()),ConcurrentSessionFilter.class)
-
.addFilterBefore(adminLoginFilter(sessionAuthenticationStrategy(authenticationStrategies)), UsernamePasswordAuthenticationFilter.class)
-
.sessionManagement()
-
.sessionAuthenticationStrategy(sessionAuthenticationStrategy(authenticationStrategies));
-
}
下面看完整的代码
-
@Configuration
-
@EnableWebSecurity
-
@EnableGlobalMethodSecurity(prePostEnabled = true)
-
public
class
PortalSecurityConfig2
extends
WebSecurityConfigurerAdapter {
-
@Autowired
-
private AdminLoginService adminDetailsService;
-
@Bean
-
public PasswordEncoder
passwordEncoder
() {
-
return
new
BCryptPasswordEncoder();
-
}
-
-
public AdminLoginFilter
adminLoginFilter
(CompositeSessionAuthenticationStrategy strategy)
throws Exception {
-
AdminLoginFilter
adminLoginFilter
=
new
AdminLoginFilter();
-
adminLoginFilter.setFilterProcessesUrl(
"/admin/login");
-
adminLoginFilter.setAuthenticationManager(authenticationManagerBean());
-
adminLoginFilter.setSessionAuthenticationStrategy(strategy);
-
return adminLoginFilter;
-
}
-
@Override
-
protected
void
configure
(HttpSecurity http)
throws Exception {
-
List<SessionAuthenticationStrategy> authenticationStrategies = Arrays.asList(
-
controlAuthenticationStrategy(sessionRegistry()),
-
sessionFixationProtectionStrategy(),
-
registerSessionAuthenticationStrategy(sessionRegistry())
-
);
-
http
-
.authorizeRequests().anyRequest().authenticated()
-
.and()
-
.addFilterBefore(concurrentSessionFilter(sessionRegistry()), ConcurrentSessionFilter.class)
-
.addFilterBefore(adminLoginFilter(sessionAuthenticationStrategy(authenticationStrategies)), UsernamePasswordAuthenticationFilter.class)
-
.sessionManagement()
-
.sessionAuthenticationStrategy(sessionAuthenticationStrategy(authenticationStrategies));
-
-
}
-
@Override
-
protected
void
configure
(final AuthenticationManagerBuilder auth)
throws Exception {
-
auth.userDetailsService(adminDetailsService);
-
}
-
@Bean
-
public SessionRegistry
sessionRegistry
(){
-
return
new
SessionRegistryImpl();
-
}
-
-
@Bean
-
public ConcurrentSessionFilter
concurrentSessionFilter
(SessionRegistry sessionRegistry){
-
return
new
ConcurrentSessionFilter(sessionRegistry);
-
}
-
@Bean
-
public ConcurrentSessionControlAuthenticationStrategy
controlAuthenticationStrategy
(SessionRegistry sessionRegistry){
-
ConcurrentSessionControlAuthenticationStrategy
strategy
=
new
ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
-
strategy.setMaximumSessions(
1);
-
return strategy;
-
}
-
-
@Bean
-
public SessionFixationProtectionStrategy
sessionFixationProtectionStrategy
(){
-
return
new
SessionFixationProtectionStrategy();
-
}
-
-
@Bean
-
public RegisterSessionAuthenticationStrategy
registerSessionAuthenticationStrategy
(SessionRegistry sessionRegistry){
-
return
new
RegisterSessionAuthenticationStrategy(sessionRegistry);
-
}
-
@Bean
-
public CompositeSessionAuthenticationStrategy
sessionAuthenticationStrategy
(List<SessionAuthenticationStrategy> authenticationStrategies){
-
return
new
CompositeSessionAuthenticationStrategy(authenticationStrategies);
-
}
-
}
希望以上内容能帮到你。
转载:https://blog.csdn.net/u011492260/article/details/129099028
查看评论
