浏览代码

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 年之前
父节点
当前提交
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
             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>
             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
         <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
         <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>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>ApplicationContext</literal>, as Spring Security classes implement Spring's
             <literal>MessageSourceAware</literal> interface and expect the message resolver to be
             <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
             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
             register a bean inside your application context to refer to the messages. An example is
             shown below:</para>
             shown below:</para>
-        <para> <programlisting><![CDATA[
+        <para>
+            <programlisting><![CDATA[
 <bean id="messageSource"
 <bean id="messageSource"
     class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
     class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
-  <property name="basename" value="org/springframework/security/messages"/>
+  <property name="basename" value="classpath:org/springframework/security/messages"/>
 </bean>
 </bean>
-]]></programlisting> </para>
+]]></programlisting>
+        </para>
         <para>The <literal>messages.properties</literal> is named in accordance with standard
         <para>The <literal>messages.properties</literal> is named in accordance with standard
             resource bundles and represents the default language supported by Spring Security
             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
         <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
             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
             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
             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
             logging a JIRA task and attaching your appropriately-named localized version of
             <literal>messages.properties</literal>.</para>
             <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>
     </section>
 </chapter>
 </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
     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">
                         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">
     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
         <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
         <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
         <property name="url" value="jdbc:hsqldb:mem:test"/>
         <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="c" uri="http://java.sun.com/jstl/core_rt" %>
 <%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_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>
         <param-value>contacts.root</param-value>
     </context-param>
     </context-param>
 
 
+    <filter>
+        <filter-name>localizationFilter</filter-name>
+        <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
+    </filter>
+
     <filter>
     <filter>
         <filter-name>springSecurityFilterChain</filter-name>
         <filter-name>springSecurityFilterChain</filter-name>
         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
     </filter>
     </filter>
 
 
+    <filter-mapping>
+        <filter-name>localizationFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
     <filter-mapping>
     <filter-mapping>
       <filter-name>springSecurityFilterChain</filter-name>
       <filter-name>springSecurityFilterChain</filter-name>
       <url-pattern>/*</url-pattern>
       <url-pattern>/*</url-pattern>

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

@@ -6,17 +6,17 @@
     <title>Access Denied</title>
     <title>Access Denied</title>
   </head>
   </head>
 
 
-  <body>
+<body>
 <h1>Sorry, access is denied</h1>
 <h1>Sorry, access is denied</h1>
 
 
 <p>
 <p>
 <%= request.getAttribute("SPRING_SECURITY_403_EXCEPTION")%>
 <%= request.getAttribute("SPRING_SECURITY_403_EXCEPTION")%>
 </p>
 </p>
 <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>
 </p>
-  </body>
+</body>
 </html>
 </html>

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

@@ -1,9 +1,8 @@
 <%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
 <%@ 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.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>
 <html>
   <head>
   <head>
@@ -16,7 +15,7 @@
     <c:if test="${not empty param.login_error}">
     <c:if test="${not empty param.login_error}">
       <font color="red">
       <font color="red">
         Your 'Exit User' attempt was not successful, try again.<br/><br/>
         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>
       </font>
     </c:if>
     </c:if>
 
 
@@ -24,16 +23,13 @@
       <table>
       <table>
         <tr><td>Current User:</td><td>
         <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>
          </td></tr>
         <tr><td colspan='2'><input name="exit" type="submit" value="Exit"></td></tr>
         <tr><td colspan='2'><input name="exit" type="submit" value="Exit"></td></tr>
       </table>
       </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' %>
 <%@ taglib prefix='c' uri='http://java.sun.com/jstl/core_rt' %>
+<%@ page pageEncoding="UTF-8" %>
 
 
 <html>
 <html>
   <head>
   <head>
@@ -19,6 +20,7 @@
     <p>username <b>jane</b>, password <b>wombat</b>
     <p>username <b>jane</b>, password <b>wombat</b>
     <p>
     <p>
 
 
+    <p>Locale is: <%= request.getLocale() %></p>
     <%-- this form-login-page form is also used as the
     <%-- this form-login-page form is also used as the
          form-error-page to ask for a login again.
          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' %>
 <%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
 <%@ page import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter" %>
 <%@ page import="org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter" %>
 <%@ page import="org.springframework.security.core.AuthenticationException" %>
 <%@ page import="org.springframework.security.core.AuthenticationException" %>
+<%@ page pageEncoding="UTF-8" %>
 
 
 <html>
 <html>
   <head>
   <head>