案例1:當使用者在第2台電腦登入時,第1台電腦抛出錯誤資訊,并下線
- 在security配置類中添加如下
.and()
.sessionManagement()// session管理
// 設定最大session數量為1
.maximumSessions(1)
- 測試1:用edge浏覽器模拟第1台電腦,用谷歌浏覽器模拟第2台電腦,在edge浏覽器認證成功後,再去谷歌浏覽器認證,谷歌浏覽器認證成功後,重新整理edge浏覽器,提示如下錯誤資訊
- 自定義錯誤資訊
- 編寫處理類
public class CustomSessionInformationExpiredStrategy implements SessionInformationExpiredStrategy {
// 注入認證失敗的處理器
@Autowired
CustomAuthenticationFailureHandler customAuthenticationFailureHandler;
@Override
public void onExpiredSessionDetected(SessionInformationExpiredEvent event) throws IOException {
// 1. 擷取使用者名
UserDetails userDetails =
(UserDetails)event.getSessionInformation().getPrincipal();
// 定義錯誤資訊
AuthenticationException exception =
new AuthenticationServiceException(
String.format("[%s] 使用者在另外一台電腦登入,您已被下線", userDetails.getUsername()));
try {
// 當使用者在多台電腦登入後,設定1個狀态為true
event.getRequest().setAttribute("toAuthentication" , true);
// 将異常資訊傳給認證失敗處理器
customAuthenticationFailureHandler
.onAuthenticationFailure(event.getRequest(), event.getResponse(), exception);
} catch (ServletException e) {
e.printStackTrace();
}
}
}
- 配置失敗處理器
@Component("customAuthenticationFailureHandler")
public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
/**
* @param exception 認證失敗時抛出異常
*/
@Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
// 認證失敗響應JSON字元串,
MengxueguResult result = MengxueguResult.build(HttpStatus.UNAUTHORIZED.value(), exception.getMessage());
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(result.toJsonString());
System.out.println("CustomAuthenticationFailureHandler ---> error");
// 如果下面有值,則認為是多端登入,則抛出多端登入的異常;否則抛出認證失敗的異常
Object toAuthentication = request.getAttribute("toAuthentication");
if (toAuthentication != null) {
error1();
} else {
error2();
}
}
public void error1() {
System.out.println("目前為使用者在多台電腦登入抛出的異常!");
}
public void error2() {
System.out.println("目前為使用者認證失敗抛出的異常!");
}
}
- 配置管理容器
@Configuration
public class SecurityConfigBean {
/**
* 當有其他類實作SessionInformationExpiredStrategy接口時,并添加@Component注解時
* 則使用其他類作為session超出最大限制的處理
* 沒有其他類實作時
* 則預設使用CustomSessionInformationExpiredStrategy處理session超出最大限制的處理
* @return
*/
@Bean
@ConditionalOnMissingBean(SessionInformationExpiredStrategy.class)
public SessionInformationExpiredStrategy sessionInformationExpiredStrategy() {
return new CustomSessionInformationExpiredStrategy();
}
}
- 配置security配置類
// 注入
@Autowired
private SessionInformationExpiredStrategy sessionInformationExpiredStrategy;
// 配置
.and()
.sessionManagement()// session管理
// 設定最大session數量為1
.maximumSessions(1)
// 設定超過最大session數量後的處理
.expiredSessionStrategy(sessionInformationExpiredStrategy)
- 測試2:用edge浏覽器模拟第1台電腦,用谷歌浏覽器模拟第2台電腦,在edge浏覽器認證成功後,再去谷歌浏覽器認證,谷歌浏覽器認證成功後,重新整理edge浏覽器,提示如下錯誤資訊
# 控制台列印入下
11:55:13.397 INFO 19888 --- [nio-8080-exec-4] c.y.s.service.CustomUserDetailsService : 請求認證的使用者名: admin
CustomAuthenticationFailureHandler ---> error
目前為使用者在多台電腦登入抛出的異常!
- 測試認證失敗:認證時輸入錯誤的使用者名和密碼
# 控制台列印如下
12:12:51.770 INFO 19888 --- [nio-8080-exec-8] c.y.s.service.CustomUserDetailsService : 請求認證的使用者名: admin
CustomAuthenticationFailureHandler ---> error
目前為使用者認證失敗抛出的異常!
案例2:當使用者在第1台電腦認證成功後,再在第2台電腦登入,這是不允許在第2台電腦登入
-
使用記住我功能時,不能設定maxSessionsPreventsLogin(true)
- 在security配置類中配置如下
.and()
.sessionManagement()// session管理
// 設定最大session數量為1
.maximumSessions(1)
// 設定超過最大session數量後的處理
.expiredSessionStrategy(sessionInformationExpiredStrategy)// 當使用者達到最大session數後,則調用此處的實作
.maxSessionsPreventsLogin(true) // 當一個使用者達到最大session數,則不允許後面再登入
- 測試:在edge浏覽器認證成功,之後在聯想浏覽器認證
# 控制台列印如下
13:14:04.169 INFO 23736 --- [nio-8080-exec-9] c.y.s.service.CustomUserDetailsService : 請求認證的使用者名: admin
CustomAuthenticationFailureHandler ---> error
目前為使用者認證失敗抛出的異常!
案例3:隻允許1台電腦登入;第1台電腦使用使用者名+密碼登入,設定第2台電腦不能使用使用者名+密碼或手機号+短信
- 如果在目前項目中可以使用使用者名+密碼認證,也可以使用手機号+驗證碼認證;在設定了不允許第2台電腦登入的情況下,第1台電腦使用使用者名+密碼認證,第2台電腦使用手機号+短信認證也能認證,正确邏輯是第2台電腦既不能使用使用者名+密碼認證,也不能使用手機号+短信認證,說明之前設定的隻允許1台電腦登入無效
# 在MobileAuthenticationConfig中配置如下
// session重複登入 管理
mobileAuthenticationFilter.setSessionAuthenticationStrategy(http.getSharedObject(SessionAuthenticationStrategy.class));