SEC-1527: Internationalization of contacts sample (Adding message resource bundle and RequestContextFilter). Re-working of L12n section of manual to mention existing localized message files and use of RequestContextFilter.

This commit is contained in:
Luke Taylor 2010-08-14 01:07:51 +01:00
parent 281d77271e
commit 992566b6cb
8 changed files with 58 additions and 37 deletions

View File

@ -648,30 +648,31 @@ Successfully authenticated. Security context contains: \
anything as by default all Security Security messages are in English. If you need to
support other locales, everything you need to know is contained in this section.</para>
<para>All exception messages can be localized, including messages related to authentication
failures and access being denied (authorization failures). Exceptions and logging that
is focused on developers or system deployers (including incorrect attributes, interface
contract violations, using incorrect constructors, startup time validation, debug-level
logging) etc are not localized and instead are hard-coded in English within Spring
Security's code.</para>
failures and access being denied (authorization failures). Exceptions and logging
messages that are focused on developers or system deployers (including incorrect
attributes, interface contract violations, using incorrect constructors, startup time
validation, debug-level logging) are not localized and instead are hard-coded in English
within Spring Security's code.</para>
<para>Shipping in the <literal>spring-security-core-xx.jar</literal> you will find an
<literal>org.springframework.security</literal> package that in turn contains a
<literal>messages.properties</literal> file. This should be referred to by your
<literal>messages.properties</literal> file, as well as localized versions for some
common languages. This should be referred to by your
<literal>ApplicationContext</literal>, as Spring Security classes implement Spring's
<literal>MessageSourceAware</literal> interface and expect the message resolver to be
dependency injected at application context startup time. Usually all you need to do is
register a bean inside your application context to refer to the messages. An example is
shown below:</para>
<para> <programlisting><![CDATA[
<para>
<programlisting><![CDATA[
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="org/springframework/security/messages"/>
<property name="basename" value="classpath:org/springframework/security/messages"/>
</bean>
]]></programlisting> </para>
]]></programlisting>
</para>
<para>The <literal>messages.properties</literal> is named in accordance with standard
resource bundles and represents the default language supported by Spring Security
messages. This default file is in English. If you do not register a message source,
Spring Security will still work correctly and fallback to hard-coded English versions of
the messages.</para>
messages. This default file is in English. </para>
<para>If you wish to customize the <literal>messages.properties</literal> file, or support
other languages, you should copy the file, rename it accordingly, and register it inside
the above bean definition. There are not a large number of message keys inside this
@ -679,13 +680,19 @@ Successfully authenticated. Security context contains: \
localization of this file, please consider sharing your work with the community by
logging a JIRA task and attaching your appropriately-named localized version of
<literal>messages.properties</literal>.</para>
<para>Rounding out the discussion on localization is the Spring
<literal>ThreadLocal</literal> known as
<classname>org.springframework.context.i18n.LocaleContextHolder</classname>. You should
set the <classname>LocaleContextHolder</classname> to represent the preferred
<literal>Locale</literal> of each user. Spring Security will attempt to locate a message
from the message source using the <literal>Locale</literal> obtained from this
<literal>ThreadLocal</literal>. Please refer to the Spring Framework documentation for
further details on using <literal>LocaleContextHolder</literal>.</para>
<para>Spring Security relies on Spring's localization support in order to actually lookup
the appropriate message. In order for this to work, you have to make sure that the
locale from the incoming request is stored in Spring's
<classname>org.springframework.context.i18n.LocaleContextHolder</classname>. Spring
MVC's <classname>DispatcherServlet</classname> does this for your application
automatically, but since Spring Security's filters are invoked before this, the
<classname>LocaleContextHolder</classname> needs to be set up to contain the correct
<literal>Locale</literal> before the filters are called. You can either do this in a
filter yourself (which must come before the Spring Security filters in
<filename>web.xml</filename>) or you can use Spring's
<classname>RequestContextFilter</classname>. Please refer to the Spring Framework
documentation for further details on using localization with Spring. </para>
<para>The <quote>contacts</quote> sample application is set up to use localized messages.
</para>
</section>
</chapter>

View File

@ -13,6 +13,10 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:org/springframework/security/messages"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
<property name="url" value="jdbc:hsqldb:mem:test"/>

View File

@ -3,3 +3,4 @@
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt" %>
<%@ page pageEncoding="UTF-8" %>

View File

@ -31,11 +31,21 @@
<param-value>contacts.root</param-value>
</context-param>
<filter>
<filter-name>localizationFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>localizationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>

View File

@ -6,17 +6,17 @@
<title>Access Denied</title>
</head>
<body>
<body>
<h1>Sorry, access is denied</h1>
<p>
<%= request.getAttribute("SPRING_SECURITY_403_EXCEPTION")%>
</p>
<p>
<% Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) { %>
Authentication object as a String: <%= auth.toString() %><BR><BR>
<% Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) { %>
Authentication object as a String: <%= auth.toString() %><br /><br />
<% } %>
</p>
</body>
</body>
</html>

View File

@ -1,9 +1,8 @@
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %>
<%@ page import="org.springframework.security.core.Authentication" %>
<%@ page import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter" %>
<%@ page import="org.springframework.security.core.AuthenticationException" %>
<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %>
<%@ page pageEncoding="UTF-8" %>
<html>
<head>
@ -16,7 +15,7 @@
<c:if test="${not empty param.login_error}">
<font color="red">
Your 'Exit User' attempt was not successful, try again.<br/><br/>
Reason: <%= ((AuthenticationException) session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
Reason: <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/>
</font>
</c:if>
@ -24,16 +23,13 @@
<table>
<tr><td>Current User:</td><td>
<%
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) { %>
<%= auth.getPrincipal().toString() %>
<% } %>
<%
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) { %>
<%= auth.getPrincipal().toString() %>
<% } %>
</td></tr>
<tr><td colspan='2'><input name="exit" type="submit" value="Exit"></td></tr>
</table>

View File

@ -1,4 +1,5 @@
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt' %>
<%@ page pageEncoding="UTF-8" %>
<html>
<head>
@ -19,6 +20,7 @@
<p>username <b>jane</b>, password <b>wombat</b>
<p>
<p>Locale is: <%= request.getLocale() %></p>
<%-- this form-login-page form is also used as the
form-error-page to ask for a login again.
--%>

View File

@ -1,6 +1,7 @@
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
<%@ page import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter" %>
<%@ page import="org.springframework.security.core.AuthenticationException" %>
<%@ page pageEncoding="UTF-8" %>
<html>
<head>