2011-12-16 40 views
10

Tôi muốn thay đổi ngôn ngữ sau khi đăng nhập vào một miền địa phương mặc định được lưu trữ trong tài khoản người dùng Ứng dụng Spring MVC (3.0) với Spring Security (3.0).Thay đổi ngôn ngữ khi đăng nhập

Tôi đã sử dụng LocaleChangeInterceptor để người dùng (không đăng nhập, đăng nhập) có thể thay đổi ngôn ngữ của nó (mặc định từ tiêu đề chấp nhận). Nhưng khách hàng thực sự muốn mặc định tài khoản cụ thể đó.

Vì vậy, câu hỏi của tôi là, cách tốt nhất để thay đổi ngôn ngữ sau khi đăng nhập là gì hoặc đã có một số chức năng xây dựng trong Spring/Security chưa?

+1

Vì bạn đã có cơ chế để thay đổi vị trí, bạn có thể tạo ra một tùy chỉnh [ 'AuthenticationSuccessHandler'] (http://static.springsource.org/spring- security/site/docs/3.0.x/apidocs/org/springframework/security/web/authentication/AuthenticationSuccessHandler.html) để chặn đăng nhập và thay đổi ngôn ngữ dựa trên tùy chọn của người dùng. Kiểm tra [ở đây] (http://static.springsource.org/spring-security/site/docs/3.0.x/reference/springsecurity-single.html#nsa-form-login) và [tại đây] (http: // stackoverflow.com/a/6612634/468508) để biết thêm thông tin. – bluefoot

Trả lời

8

Giải pháp tốt nhất tôi có thể tìm được là xử lý điều này trong AuthenticationSuccessHandler.

Sau đây là một số mã tôi đã viết cho khởi động của tôi:

public class LocaleSettingAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { 
    @Resource 
    private LocaleResolver localeResolver; 

    @Override 
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { 
     setLocale(authentication, request, response); 
     super.onAuthenticationSuccess(request, response, authentication); 
    } 

    protected void setLocale(Authentication authentication, HttpServletRequest request, HttpServletResponse response) { 
     if (authentication != null) { 
      Object principal = authentication.getPrincipal(); 
      if (principal instanceof LocaleProvider) { 
       LocaleProvider localeProvider = (LocaleProvider) principal; 
       Locale providedLocale = localeProvider.getLocale(); 
       localeResolver.setLocale(request, response, providedLocale); 
      } 
     } 
    } 
} 

Và giao diện sau đây cần được cung cấp bởi lớp chính của bạn. Điều này là không cần thiết nhưng tôi đang sử dụng nó vì tôi có nhiều đối tượng có khả năng cung cấp ngôn ngữ cho phiên.

public interface LocaleProvider {  
    Locale getLocale();  
} 

đoạn Cấu hình:

<security:http ...> 
    <security:custom-filter ref="usernamePasswordAuthenticationFilter" position="FORM_LOGIN_FILTER"/> 
</security:http> 

<bean id="usernamePasswordAuthenticationFilter" 
    class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"> 
    <property name="filterProcessesUrl" value="/login/j_spring_security_check"/> 
    <property name="authenticationManager" ref="authenticationManager"/> 
    <property name="authenticationFailureHandler"> 
     <bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> 
      <property name="defaultFailureUrl" value="/login?login_error=t"/> 
     </bean> 
    </property> 
    <property name="authenticationSuccessHandler"> 
     <bean class="LocaleSettingAuthenticationSuccessHandler"> 
    </property> 
</bean> 
+0

cảm ơn: ý tưởng đó sẽ hoạt động, tôi đã sửa đổi nó một chút để sử dụng các sự kiện (ngược lại với InteractiveAuthenticationSuccessEvent và AuthenticationSuccessEvent chứa đối tượng Yêu cầu và phản hồi) – Ralph

+0

Tôi đã thêm đoạn mã cấu hình để hoàn thành, để chỉ ra đâu và cách xác thực 'authenticationSuccessHandler 'có thể được thiết lập. - Nếu bạn không thích nó, sau đó xóa một phần từ câu trả lời - Tôi xin lỗi rằng tôi đã chỉnh sửa câu trả lời yor, nhưng nó đã được nhiều văn bản cho một bình luận. – Ralph

+0

dường như không hoạt động nữa, localeResolver alway null –

2

Sử dụng SessionLocaleResolver và xây dựng nó làm hạt được gọi là "localeResolver". LocaleResolver này sẽ giải quyết các ngôn ngữ bằng cách đầu tiên kiểm tra miền địa phương mặc định mà trình giải quyết được xây dựng. Nếu đó là null, nó sẽ kiểm tra nếu một miền địa phương đã được lưu trữ trong phiên, và nếu đó là null, nó sẽ thiết lập miền địa phương phiên dựa trên tiêu đề Accept-Language trong yêu cầu.

Sau khi người dùng đăng nhập, bạn có thể gọi localeResolver.setLocale để lưu ngôn ngữ vào phiên cho bạn, bạn có thể thực hiện việc này trong bộ lọc servlet (đảm bảo xác định nó trong web.xml SAU bộ lọc).

Để truy cập vào localeResolver của bạn (hoặc đậu khác) từ bộ lọc của bạn, làm một cái gì đó như thế này trong phương thức init:

@Override 
public void init(FilterConfig fc) throws ServletException { 
    ServletContext servletContext = fc.getServletContext(); 
    ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(servletContext); 
    this.localeResolver = context.getBean(SessionLocaleResolver.class); 
} 

Sau đó, trong doFilterMethod, bạn sẽ có thể cast ServletRequest đến một HttpServletRequest, gọi getRemoteUser, thực hiện bất kỳ logic nghiệp vụ nào để định nghĩa miền địa phương của người dùng đó và gọi setLocale trên LocaleResolver.

Cá nhân, tôi không quan tâm đến SessionLocaleResolver để sử dụng địa phương mặc định trước tiên (tôi thích cuối cùng), tuy nhiên nó thực sự dễ dàng mở rộng và ghi đè. Nếu bạn quan tâm đến việc kiểm tra phiên giao dịch, sau đó yêu cầu, sau đó mặc định, sử dụng như sau:

import org.springframework.stereotype.Component; 
import org.springframework.web.util.WebUtils; 

import javax.servlet.http.HttpServletRequest; 
import java.util.Locale; 

// The Spring SessionLocaleResolver loads the default locale prior 
// to the requests locale, we want the reverse. 
@Component("localeResolver") 
public class SessionLocaleResolver extends org.springframework.web.servlet.i18n.SessionLocaleResolver{ 

    public SessionLocaleResolver(){ 
     //TODO: make this configurable 
     this.setDefaultLocale(new Locale("en", "US")); 
    } 

    @Override 
    public Locale resolveLocale(HttpServletRequest request) { 
     Locale locale = (Locale) WebUtils.getSessionAttribute(request, LOCALE_SESSION_ATTRIBUTE_NAME); 
     if (locale == null) { 
      locale = determineDefaultLocale(request); 
     } 
     return locale; 
    } 

    @Override 
    protected Locale determineDefaultLocale(HttpServletRequest request) { 
     Locale defaultLocale = request.getLocale(); 
     if (defaultLocale == null) { 
      defaultLocale = getDefaultLocale(); 
     } 
     return defaultLocale; 
    } 

} 
+0

Vấn đề chính không phải là phương pháp nên được gọi để thay đổi địa phương. Vấn đề chính là kích hoạt một số phương thức sau khi đăng nhập (có quyền truy cập vào các chi tiết đăng nhập (cho tên người dùng) và Local Resolver để thay đổi cục bộ) – Ralph

+0

Tôi đã cập nhật câu trả lời ở trên. – aweigold

+0

Xin lỗi nhưng điều này không giải quyết được vấn đề. Nó không kích hoạt quá trình sau khi đăng nhập. Bộ lọc sẽ thay đổi địa phương của người dùng với mọi yêu cầu sau khi người dùng đăng nhập. Đó không phải là những gì tôi được yêu cầu: Tôi sử dụng một LocaleChangeInterceptor điều này có nghĩa là người dùng có thể thay đổi độc lập đăng nhập của nó mặc định. chỉ là một mặc định - người dùng phải có khả năng thay đổi nó sau này trên throug mà interceptor. --- Dù sao tôi đã thực hiện một giải pháp như vậy (với một Spring Interceptor thay vì ServletFilter) nhưng nó là một hack. – Ralph

0

workarround hiện tại của tôi hoạt động theo cách này (nhưng vẫn là một hack, bởi vì nó không được kích hoạt bởi đăng nhập quy trình):

Tôi có Trình xử lý chặn thủ công để chặn mọi yêu cầu. Nó sẽ luôn luôn kiểm tra nếu đã có một lá cờ (LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) trong phiên người dùng cho biết rằng địa phương đã được cập nhật. Nếu không có cờ như vậy, thì trình chặn sẽ kiểm tra xem yêu cầu có thuộc về người dùng được xác thực hay không. Nếu đó là người dùng đã được xác thực thì bản cập nhật địa phương mặc dù là localResolver và đặt cờ (LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) trong phiên

Công cụ cờ này là cần thiết, vì địa chỉ phải thay đổi chỉ sau khi đăng nhập. Vì vậy, sau này người dùng có thể thay đổi cục bộ một lần nữa thông qua bộ chặn đánh chặn thay đổi cục bộ thông thường.

public class LocalChangeUserInterceptor extends HandlerInterceptorAdapter { 

    /** Session key, used to mark if the local is set. */ 
    private static final String LOCALE_ALREADY_SET_SESSION_ATTRIBUTE = "LocalChangeUserInterceptor.localeAlreadySet"; 

    /** The locale resolver. */ 
    @Resource 
    private LocaleResolver localeResolver; 

    @Resource 
    private UserService userService; 

    @Override 
    public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler) 
      throws Exception { 
     if (!isLocaleAlreadySet(request)) { 
      User currentAuthenticatedUser = getCurrentUserOrNull(); 
      if (currentAuthenticatedUser != null) { 
       this.localeResolver.setLocale(request, response, currentAuthenticatedUser.getLocale()); 
       request.getSession().setAttribute(LOCALE_ALREADY_SET_SESSION_ATTRIBUTE, "true"); 
      } 
     } 
     return true; 
    } 

    /** 
    * Check if there is an session attribute that states that the local is already set once. 
    * @param request the request 
    * @return true, if is locale already set 
    */ 
    private boolean isLocaleAlreadySet(final HttpServletRequest request) { 
     HttpSession sessionOrNull = request.getSession(false); 
     return ((sessionOrNull != null) && (sessionOrNull.getAttribute(LOCALE_ALREADY_SET_SESSION_ATTRIBUTE) != null)); 
    } 

    /** 
    * Get the current user or null if there is no current user. 
    * @return the current user 
    */ 
    public User getCurrentUserOrNull() { 
     Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
     if ((authentication == null) || (authentication instanceof AnonymousAuthenticationToken)) { 
      return null; 
     } else { 
      return this.userService.getUser(authentication); 
     } 
    } 
} 
Các vấn đề liên quan