2012-05-30 58 views
8

我們正在開發一個帶有jQuery移動版的移動應用程序,並且想要在彈簧安全性正確設置的spring 3.1.x後端上以編程方式驗證用戶身份。春季安全:以編程方式登錄

POST請求被髮送到包含用戶名和密碼的後端(使用jQuery的$ .post),然後服務器驗證憑據是否正確並登錄到用戶。

服務器似乎在SecurityContext中正確設置了身份驗證,但是當我們向服務器發出第二個請求($ .get到需要登錄的頁面)時,安全細節似乎不會被記住,並且匿名令牌似乎在上下文中。

這是控制器處理登錄(簡潔,刪除密碼校驗)的方法:

@RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json") 
@ResponseBody 
public Map<String, String> login(@RequestParam String username, @RequestParam String password, HttpServletRequest request) { 
    Map<String, String> response = new HashMap<String, String>(); 

    User u = userService.findByAccountName(username); 

    if (u != null && u.hasRole("inspector")) { 
     UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password); 
     try { 
      Authentication auth = authenticationManager.authenticate(token); 
      SecurityContextHolder.getContext().setAuthentication(auth); 

      response.put("status", "true"); 
      return response; 
     } catch (BadCredentialsException ex) { 
      response.put("status", "false"); 
      response.put("error", "Bad credentials"); 
      return response; 
     } 
    } else { 
     response.put("status", "false"); 
     response.put("error", "Invalid role"); 
     return response; 
    } 
} 

這就是我們得到的UserDetails了上下文的另一種方法:

@RequestMapping(value = "/project", method = RequestMethod.GET) 
@ResponseBody 
public String getProjects(HttpSession session) { 

    Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
    User u = userService.findByAccountName(((UserDetails) authentication.getPrincipal()).getUsername()); 
... 

春季安全配置:

<global-method-security pre-post-annotations="enabled"/> 
<http use-expressions="true" auto-config="true"> 

    <form-login login-processing-url="/static/j_spring_security_check" login-page="/" 
       authentication-failure-url="/?login_error=t"/> 

    ... 
    <intercept-url pattern="/api/**" access="permitAll"/> 
    ... 
    <remember-me key="biKey" token-validity-seconds="2419200"/> 
    <logout logout-url="/logout"/> 
</http> 

<authentication-manager alias="authenticationManager"> 
    <authentication-provider user-service-ref="udm"> 
     <password-encoder hash="md5"/> 
    </authentication-provider> 
</authentication-manager> 

這要根據工作到春季安全文檔和其他在線資源。任何想法可能是錯誤的?

+0

SecurityContextHolder默認保留策略是ThreadLocal。每個請求都在新線程中處理(實際上並不是每個線程池都是這樣,但這並不重要),並擁有自己的持有threadlocal的上下文副本。所以你在login方法中設置的身份驗證無法在getProjects方法中訪問(因爲它在另一個線程中)。你應該在某個地方保存你的認證信息(例如http會話),並在每次新的請求到達服務器時恢復認證對象(可能在servlet過濾器中) –

+1

檢查http://stackoverflow.com/questions/3923296/user-granted -authorities-always-role-anonymous – axtavt

+0

我使用由axtavt鏈接的出色答案實現了這個確切的功能。 –

回答

11

我很困惑你的配置。你已經實現了你自己的登錄控制器,但你似乎在使用Spring Security的表單登錄。我最近使用Spring Security + jQuery實現了ajax登錄。我只是實現了自己的AuthenticationSuccessHandler和AuthenticationFailureHandler來返回我需要的json響應,而不是編寫自己的控制器。只是延長SimpleUrlAuthenticationSuccessHandler和SimpleUrlAuthenticationFailureHandler覆蓋在每類的東西一樣簡單的onAuthenticationSuccess和onAuthenticationFailure方法....

public void onAuthenticationSuccess(HttpServletRequest request, 
     HttpServletResponse response, Authentication authentication) 
     throws IOException, ServletException { 
    response.getWriter().println("{\"success\": true}"); 
} 

public void onAuthenticationFailure(HttpServletRequest request, 
     HttpServletResponse response, AuthenticationException exception) 
     throws IOException, ServletException { 
    response.getWriter().println("{\"success\": false}"); 
} 

然後你就可以用類似配置表單登錄元素...

<form-login login-processing-url="/static/j_spring_security_check" login-page="/" 
      authentication-success-handler-ref="ajaxAuthenticationSuccessHandler" 
      authentication-failure-handler-ref="ajaxAuthenticationFailureHandler" 
      authentication-failure-url="/?login_error=t"/> 
+0

這工作完美...謝謝。 – HDave

+0

很高興幫助,請標記我的答案爲已接受 – hyness

+0

我會如果我可以...... – HDave