Spring security + i18n = como fazer isso funcionar em conjunto?
Minha primeira pergunta aqui e vou tentar ser específico. Eu sou bastante novo no Spring e estou tentando criar um sistema de reservas bastante simples (mas isso realmente não importa). O que importa é que estou criando um modelo básico que preencherei em páginas da Web reais. O aplicativo funciona no hibernate, mysql, também configurei o i18n e o spring security. O problema é que não posso mudar minha localidade. A única coisa que funciona é mudar o padrão. Primeiro, pesquisei MUITO pela Web e descobri que o uso de um i18n em conjunto com a segurança da primavera é mais complicado do que normalmente. O que descobri é que preciso ter um filtro adicional:
<filter>
<filter-name>localizationFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>localizationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
O que eu descobri é que esse filtro é realmente processado antes do filtro de segurança, mas não analisa a solicitação de uma forma:http://someserver.com/bla/home?locale=en
. Eu depurei e parece que não foi criado para esse fim (e é disso que eu preciso). Isso foi retirado dos exemplos de "contatos" da primavera, no entanto, neste exemplo, não consegui encontrar nenhum código que realmente estivesse direcionado para alterar o idioma. O efeito é que simplesmente não funciona. Ele sempre tenta alterar o código de idioma para o padrão. A boa notícia é que, se no modo de depuração, eu alterei manualmente o local para definir para outro, funcionou bem, então senti esperança no meu coração ...; -)
Então eu encontrei outra maneira - criando nosso próprio filtro. O que fiz foi mesclar o exemplo encontrado (não lembre o autor) junto com a maneira comoRequestContextFilter
é criado. Depois de todo oRequestContextFilter
funciona bem - apenas não analise meus pedidos. Esse é o código do novo filtro:
public class InternationalizationFilter extends OncePerRequestFilter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
protected void doFilterInternal(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain filterChain)
throws ServletException, IOException {
final String newLocale = request.getParameter("locale");
if (newLocale != null) {
final Locale locale = StringUtils.parseLocaleString(newLocale
.toLowerCase());
LocaleContextHolder.setLocale(locale);
}
try {
filterChain.doFilter(request, response);
} finally {
LocaleContextHolder.resetLocaleContext();
}
}
}
Como você pode ver, o local do parâmetro do pedido é analisado e o local está definido. Existem 2 problemas: 1. Após enviar a solicitaçãoxxxxx?locale=en
ele cria o local sem o atributo "país" (apenas o idioma está definido). Para ser sincero, não sei se há algum problema - talvez não. 2. O problema mais sério é que ele não funciona ... quero dizer, está no lugar certo na cadeia de filtros (antes da segurança), produz o local correto e o define exatamente da mesma maneira comoRequestContextFilter
... mas simplesmente não funcion
Ficaria muito feliz se alguém me dissesse como fazer o i18n funcionar com segurança por mola com base no meu exemplo ou em qualquer outro ...
Obrigado
INFORMAÇÕES ADICIONAIS: Fiz algumas experiências e parece que a instância Locale da solicitação é de alguma forma específic
Veja este código (modificou oRequestContextFilter
classe)
@Override
protected void doFilterInternal(final HttpServletRequest request,
final HttpServletResponse response, final FilterChain filterChain)
throws ServletException, IOException {
final ServletRequestAttributes attributes = new ServletRequestAttributes(
request);
final Locale l = Locale.GERMAN;
final Locale l2 = request.getLocale();
LocaleContextHolder.setLocale(l,
this.threadContextInheritable);
RequestContextHolder.setRequestAttributes(attributes,
this.threadContextInheritable);
if (logger.isDebugEnabled()) {
logger.debug("Bound request context to thread: " + request);
}
(...)
se este método:LocaleContextHolder.setLocale(l, this.threadContextInheritable);
Eu passo a localidade 'l', não funciona. Quero dizer, a localidade não muda, mesmo que seja explicitamente alterada. Por outro lado, se eu passar lá Locale 'l2', que é modificado para alemão (no modo de depuração), funciona bem!
Isso significa que, por algum motivo, a instância Locale derequest.getLocale()
é de alguma forma favorecido, talvez algo esteja acontecendo mais tarde no código que eu não conheço / entendo ...
Por favor, deixe-me saber como devo usar este i18n junto com a segurança, pois cheguei ao ponto em que devo admitir que não tenho ideia do que está acontecendo ...
- ==== - ====== - ====== - ======= - ====
SOLUÇÃO FINAL / RESPOSTA (mas ainda com pouca dúvida) Graças a Ralph, consegui resolver o meu problema. Anteriormente, eu estava indo na direção errada, mas o projeto gerado pelo roo me empurrou para frente. Parece que eu continuei adicionando o interceptador de uma maneira incorreta / não precisa (código anterior):
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="pl"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
Dessa forma, o interceptador nunca foi chamado por algum motiv
Depois de alterar o interceptor def para:
<mvc:interceptors>
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
</bean>
</mvc:interceptors>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="pl"/>
</bean>
<bean id="handlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
</bean>
... começou a funcionar bem sem outras alterações em security / web.xm
Agora, o problema se foi, mas não sei ao certo o que aconteceu. Pelo que entendi no segundo exemplo (aquele que funciona), tornei o interceptador "global". Mas por que o interceptador desativado no primeiro exemplo não funcionou? Alguma dica?
Obrigado novamente por ajuda! N.