2

我使用spring security3和spring mvc3來構建Web項目。有一個名爲index.jsp的頁面,登錄用戶名和在線用戶數將顯示在屏幕頂部的 上。有2種方式登錄系統:使用sessionRegistry登錄用戶手動驗證時不起作用

  1. 從登錄頁面,通過「j_spring_security_check」
  2. Ajax登陸與手動驗證使用默認配置後

當我使用登錄頁面登錄到指數頁面,在線信息和用戶名稱都顯示正確。 但是,當我使用ajax登錄(手動驗證)時,會出現問題:在線用戶的計數沒有更新,它始終顯示0,而用戶名可以正常顯示。控制器的 部分:

@Autowired 
@Qualifier("authenticationManager") 
AuthenticationManager authenticationManager; 
@Autowired 
SecurityContextRepository repository; 

@RequestMapping(value="/ajaxLogin") 
@ResponseBody 
public String performLogin(
     @RequestParam("j_username") String username, 
     @RequestParam("j_password") String password, 
     HttpServletRequest request, HttpServletResponse response) { 
      UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password); 
      try { 
       Authentication auth = authenticationManager.authenticate(token); 
       SecurityContextHolder.getContext().setAuthentication(auth); 
       repository.saveContext(SecurityContextHolder.getContext(), request, response); 
       logger.info("Authentication successfully! "); 
       return "{\"status\": true}"; 
      } catch (BadCredentialsException ex) { 
       return "{\"status\": false, \"error\": \"Bad Credentials\"}"; 
      } 
} 

彈簧security.xml文件我用得到

<beans:beans xmlns="http://www.springframework.org/schema/security" 
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
http://www.springframework.org/schema/security 
http://www.springframework.org/schema/security/spring-security-3.0.3.xsd"> 

<http auto-config="true" use-expressions="true">  
    <intercept-url pattern="/login" access="permitAll" /> 
    <intercept-url pattern="/index" access="permitAll" /> 
    <form-login login-page="/login" default-target-url="/index" 
     authentication-failure-url="/loginfailed" /> 
    <logout logout-success-url="/logout" /> 

    <session-management invalid-session-url="/index"> 
     <concurrency-control max-sessions="1" 
      error-if-maximum-exceeded="false" /> 
    </session-management> 
</http> 

<authentication-manager alias="authenticationManager"> 
    <authentication-provider> 
     <jdbc-user-service data-source-ref="dataSource" 

      users-by-username-query=" 
       select login_id,login_pwd, is_enabled 
       from t_user where login_id=?" 

      authorities-by-username-query=" 
       select u.login_id, r.authority from t_user u, t_roles r 
       where u.u_id = r.u_id and u.login_id =? " /> 
    </authentication-provider> 
</authentication-manager> 

法網上的登錄用戶數:

public class BaseController { 
    protected Logger logger = Logger.getLogger(this.getClass()); 

    @Autowired 
    SessionRegistry sessionRegistry; 

    @ModelAttribute("numUsers") 
    public int getNumberOfUsers() { 
     logger.info("in getNumberOfUsers() ..."); 
     return sessionRegistry.getAllPrincipals().size(); 
    } 
} 

代碼用來顯示登錄用戶名:

<div> 
     <security:authorize ifAllGranted="ROLE_USER"> 
      <p><a href="#TODO">Welcome <security:authentication property="principal.username" />!</a> &nbsp;&nbsp;&nbsp; 
      <a href="<c:url value="/j_spring_security_logout" />">Logout</a></p> 
     </security:authorize> 
    </div> 

代碼用於顯示的登錄用戶數:

<div style="color:#3CC457"> 
     ${numUsers} user(s) are logged in! 
    </div> 

我想這是因爲,當我手動身份驗證,春季安全不能爲用戶創造新的會話。我通過編寫定製的SessionCounterListener來驗證它。

public class SessionCounterListener implements HttpSessionListener { 
private Logger logger = Logger.getLogger(this.getClass()); 
private static int totalActiveSessions; 

public static int getTotalActiveSession(){ 
     return totalActiveSessions; 
} 

@Override 
public void sessionCreated(HttpSessionEvent event) { 
     totalActiveSessions++; 
     logger.info("sessionCreated - add one session into counter" + event.getSession().getId()); 
} 

@Override 
public void sessionDestroyed(HttpSessionEvent event) { 
     totalActiveSessions--; 
     logger.info("sessionDestroyed - deduct one session from counter" + event.getSession().getId()); 
} 

}

下面是動作順序日誌文件的重點內容:正常登錄 - >正常退出 - > Ajax登陸 - > AJAX註銷。

sessionDestroyed - deduct one session 1spueddcmdao019udc43k3uumw 
sessionCreated - add one session 14nro6bzyjy0x1jtvnqjx31v1 
sessionDestroyed - deduct one session 14nro6bzyjy0x1jtvnqjx31v1 
sessionCreated - add one session e6jqz5qy6412118iph66xvaa1 

其實,ajax登錄/註銷不給任何輸出。

那麼現在,我怎麼才能得到正確的登錄用戶數?爲什麼不同的認證方式有不同的方法來處理會話?任何幫助將不勝感激。

+0

使用SessionUtils。見例如:http://stackoverflow.com/questions/1013032/programmatic-use-of-spring-security – Ritesh

回答

0

在您的Spring spring-security.xml文件中,未明確允許AJAX身份驗證的網址(/ajaxLogin)。因此,請求應該被Spring阻止。我會建議補充一點:

<intercept-url pattern="/ajaxLogin" access="permitAll" /> 
+0

你好@LaurentG,我試過你的建議,但它不工作。當我使用/ ajaxLogin時,已經顯示'Welcome [email protected]',但只有用戶計數顯示爲0.請參閱日誌,系統不會觸發sessionCreated(HttpSessionEvent事件)。手動驗證後,系統將使用相同的會話ID,而正常登錄將在驗證成功後創建新的會話ID。 –

3

如你手動添加PrincipalSecurityContext,它不會增加用戶SessionRegistry。您需要手動將用戶會話添加到SessionRegistry

SecurityContextHolder.getContext().setAuthentication(auth); 
sessionRegistry.registerNewSession(request.getSession().getId(), auth.getPrincipal()); 

希望它有幫助!