2
0
Эх сурвалжийг харах

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.

Luke Taylor 15 жил өмнө
parent
commit
992566b6cb

+ 27 - 20
docs/manual/src/docbook/technical-overview.xml

@@ -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>

+ 4 - 0
samples/contacts/src/main/resources/applicationContext-common-business.xml

@@ -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"/>

+ 1 - 0
samples/contacts/src/main/webapp/WEB-INF/jsp/include.jsp

@@ -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" %>

+ 10 - 0
samples/contacts/src/main/webapp/WEB-INF/web.xml

@@ -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>

+ 5 - 5
samples/contacts/src/main/webapp/accessDenied.jsp

@@ -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>

+ 8 - 12
samples/contacts/src/main/webapp/exitUser.jsp

@@ -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>

+ 2 - 0
samples/contacts/src/main/webapp/login.jsp

@@ -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.
          --%>

+ 1 - 0
samples/contacts/src/main/webapp/switchUser.jsp

@@ -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>