2020 年 2 月 24 日 星期一

IT Skills 波林

Polin WEI – 資訊工作者的技術手札

使用 Spring Security 來記錄已登入帳號的資訊

2 min read
山姆派樂

使用 Spring Security 來記錄已登入帳號的資訊

 

 

在  Spring Boot 客製化 登入 ( Login ) 與 認證 (Authenticate) 機制Spring Boot 身份認證 (Authentication) 使用資料庫 (Database) 中客製了登入系統的程式,進一步就可以來記錄有多少登入帳號,在登出時要刪除此帳號資訊,這樣可以瞭解同時在線的總人數。要達成這個功能,要實作 Spring Security 中的 AuthenticationSuccessHandlerLogoutSuccessHandler ,並且在 WebSecurityConfigurerAdapterconfigure(HttpSecurity httpSecurity) 作設定即可。

 

  • 建立 Table: whois 來存檔記錄
DROP TABLE IF EXISTS `whois`;
CREATE TABLE whois (
 sessionId VARCHAR(255) NOT NULL,
 username VARCHAR(50) NOT NULL,
 remoteAddress VARCHAR(50),
 isLogged boolean,
 createDate datetime DEFAULT CURRENT_TIMESTAMP,
 updateDate datetime,
 createUser bigint,
 updateUser bigint,
 CONSTRAINT whois_pkey PRIMARY KEY (sessionId),
 CONSTRAINT uk_sessionId_username UNIQUE KEY(sessionId,username)
);

 

  • 撰寫 class: AppsAuthenticationSuccessHandler.java 實作 AuthenticationSuccessHandler
@Component
public class AppsAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

 @Autowired 
 SystemService sysService;
 
 @Override
 public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
   Authentication authentication) throws IOException, ServletException {
  
  HttpSession session = request.getSession(false);
  if (session != null) {
   // 將 Object 轉換成 Map
   ObjectMapper oMapper = new ObjectMapper();
   Map<String,String> authDetail = oMapper.convertValue(authentication.getDetails(),Map.class);
   Whois whois = sysService.setWhoIsOnline( authDetail , authentication.getName());
  }
  if (authentication.isAuthenticated()) {
   response.sendRedirect("/auth/home");
  } else {
   response.sendRedirect("/home");
  }

 }

}

在登入成功後的實作中,因為 authentication.getDetails() 回饋的是一個 Object,因此使用 com.fasterxml.jackson.databind.ObjectMapper 來將 authentication.getDetails() 的 Object 轉換成 Map<String,String> authDetail ,這裡要注意,第 16 行則是將資訊記錄於 table: whois 中。還有 18-22 行應該只要寫成 response.sendRedirect("/auth/home"); 即可,因為這是登入已認證的帳號才會執行。這麼寫只是為了再次確認安全性而已。最後記得引用 Annotation: @Component 來啟用它。

 

  • 撰寫 class: AppsLogoutSuccessHandler.java 實作 LogoutSuccessHandler
@Component
public class AppsLogoutSuccessHandler implements LogoutSuccessHandler {

 @Autowired 
 SystemService sysService;
 
 @Override
 public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
   throws IOException, ServletException {
  
  ObjectMapper oMapper = new ObjectMapper();
  Map<String,String> authDetail = oMapper.convertValue(authentication.getDetails(),Map.class);
  sysService.removeWhoisOnline(authDetail.get("sessionId"));
  response.sendRedirect("/logout/process");

 }

}

登出成功後的實作,也是大同小異,找到登出帳號的 sessionId ,然後記錄於 table: whois table: whois 中。

 

  • 啟用 class: AppsAuthenticationSuccessHandler.java 與  class: AppsLogoutSuccessHandler.java
@Autowired
AppsAuthenticationSuccessHandler appsAuthenticationSuccessHandler;
@Autowired
AppsLogoutSuccessHandler appsLogoutSuccessHandler;

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
 httpSecurity
  .authorizeRequests()          
   .antMatchers("/", "/home").permitAll()
   .anyRequest().authenticated()
   .and()               
  .formLogin()
   .loginPage("/login")                 
   .defaultSuccessUrl("/auth/home")                 
   .permitAll()
   .successHandler(appsAuthenticationSuccessHandler)
   .and()
  .logout()                 
   .logoutSuccessUrl("/logout/process")
   .permitAll()
   .logoutSuccessHandler(appsLogoutSuccessHandler);

}

第 17, 22 行是設定 successHandler & logoutSuccessHandler ,就是將上面兩支程式注冊即可。記錄的完整資訊會如下表。

whois

 

  • 利用 SessionRegistry 取得所有登入認證的帳號

Spring Security 提供 SessionRegistry 來取得所有登入認證的帳號,只要先建立一個 @Bean SessionRegistry 及 修改 HttpSecurity 即可。

@Bean
public SessionRegistry sessionRegistry() {
 return new SessionRegistryImpl();
}

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
 httpSecurity
   .authorizeRequests()     
    .antMatchers("/", "/home").permitAll()
    .anyRequest().authenticated()
    .and()              
   .formLogin()
    .loginPage("/login")            
    .defaultSuccessUrl("/auth/home")                    
    .permitAll()
    .successHandler(appsAuthenticationSuccessHandler)
    .and()
   .logout()                    
    .logoutSuccessUrl("/logout/process")
    .permitAll()
    .logoutSuccessHandler(appsLogoutSuccessHandler)
    .and()
   .sessionManagement()
    .maximumSessions(1).sessionRegistry(sessionRegistry());

}

記得增加第 24,25 行,以啟用 SessionRegistry 來取得所有登入認證的帳號。

 

參考: https://www.baeldung.com/spring-security-track-logged-in-users

 

 

Copyright © All rights reserved. | Newsphere by AF themes.