mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-05-30 08:42:13 +00:00
manual updates
This commit is contained in:
parent
3f603dfdd8
commit
d5aec71fac
@ -97,8 +97,23 @@
|
||||
Security.</para>
|
||||
</partintro>
|
||||
<xi:include href="technical-overview.xml"/>
|
||||
<xi:include href="supporting-infrastructure.xml"/>
|
||||
<xi:include href="channel-security.xml"/>
|
||||
<!--xi:include href="supporting-infrastructure.xml"/-->
|
||||
<!-- xi:include href="channel-security.xml"/ -->
|
||||
</part>
|
||||
|
||||
<part xml:id="webapp-security" >
|
||||
<title>Web Application Security</title>
|
||||
<partintro>
|
||||
<para>
|
||||
Most Spring Security users will be using the framework in enterprise applications which
|
||||
make user of the HTTP and the Servlet API. In this part we'll take a look at how Spring Security provides
|
||||
authentication and access-control features for the web layer of an application. We'll look
|
||||
behind the facade of the namespace and see which classes and interfaces are actually assembled to provide web-layer
|
||||
security. In some situations it is necessary to use traditional bean configuration to provide full control over
|
||||
the configuration, so we'll also see how to configure these classes directly without the namespace.
|
||||
</para>
|
||||
</partintro>
|
||||
<xi:include href="supporting-infrastructure.xml"/>
|
||||
</part>
|
||||
<part xml:id="authentication">
|
||||
<title>Authentication</title>
|
||||
|
@ -1,97 +1,32 @@
|
||||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="supporting-infrastructure" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="web-infrastructure" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
|
||||
<info><title>Supporting Infrastructure</title></info>
|
||||
|
||||
|
||||
<para>This chapter introduces some of the supplementary and supporting
|
||||
infrastructure used by Spring Security. If a capability is not directly
|
||||
related to security, yet included in the Spring Security project, we
|
||||
will discuss it in this chapter.</para>
|
||||
|
||||
<section xml:id="localization">
|
||||
<title>Localization</title>
|
||||
<para>Spring Security supports localization of exception messages that
|
||||
end users are likely to see. If your application is designed for
|
||||
English users, you don't need to do 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>
|
||||
|
||||
<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>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[
|
||||
<bean id="messageSource"
|
||||
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
|
||||
<property name="basename" value="org/springframework/security/messages"/>
|
||||
</bean>
|
||||
]]></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>
|
||||
|
||||
<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 file, so localization should not be
|
||||
considered a major initiative. If you do perform 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
|
||||
<literal>org.springframework.context.i18n.LocaleContextHolder</literal>.
|
||||
You should set the <literal>LocaleContextHolder</literal> 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 Spring documentation
|
||||
for further details on using <literal>LocaleContextHolder</literal>
|
||||
and the helper classes that can automatically set it for you (eg
|
||||
<literal>AcceptHeaderLocaleResolver</literal>,
|
||||
<literal>CookieLocaleResolver</literal>,
|
||||
<literal>FixedLocaleResolver</literal>,
|
||||
<literal>SessionLocaleResolver</literal> etc)</para>
|
||||
</section>
|
||||
<info><title>Web Security Infrastructure</title></info>
|
||||
|
||||
<section xml:id="filters">
|
||||
<info><title>Filters</title></info>
|
||||
<title>Spring Security Filters</title>
|
||||
|
||||
<para>Spring Security uses many filters, as referred to throughout the
|
||||
remainder of this reference guide. If you are using <link xlink:href="#ns-config">namespace configuration</link>,
|
||||
then the you don't usually have to declare the filter beans explicitly. There may be times when you want full control
|
||||
over the security filter chain, either because you are using features which aren't supported in the namespace, or you
|
||||
are using your own customized versions of classes.</para>
|
||||
<para>In this case, you have a choice in how these filters are added to your web application, in that you can use either
|
||||
Spring's <literal>DelegatingFilterProxy</literal> or
|
||||
<classname>FilterChainProxy</classname>. We'll look at both below.</para>
|
||||
|
||||
<para>When using <literal>DelegatingFilterProxy</literal>, you will see
|
||||
something like this in the web.xml file:
|
||||
|
||||
<para>Spring Security's web application features are implemented using standard servlet filters. It doesn't use
|
||||
servlets or any other servlet-based frameworks (such as Spring MVC) internally. So it has no strong links to any
|
||||
particular web technology - it deals in <classname>HttpServletRequest</classname>s and <classname>HttpServletResponse</classname>s
|
||||
and doesn't care whether the requests come from a browser, a web service client, an <classname>HttpInvoker</classname> or an AJAX application.
|
||||
</para>
|
||||
<para>
|
||||
Spring Security maintains a filter chain internally where each of the filters has a particular responsibility and filters are added or removed
|
||||
depending on which services are required. The ordering of the filters is important as there are dependencies between them.
|
||||
If you have been using <link xlink:href="#ns-config">namespace configuration</link>, then the filters are automatically configured for you
|
||||
and you don't have to define any Spring beans explicitly but here may be times when you want full control over the security filter chain,
|
||||
either because you are using features which aren't supported in the namespace, or you are using your own customized versions of classes.</para>
|
||||
|
||||
<section xml:id="delegating-filter-proxy">
|
||||
<title><classname>DelegatingFilterProxy</classname></title>
|
||||
<para>
|
||||
When using servlet filters, you obviously need to declare them in your <filename>web.xml</filename>, or they will be ignored
|
||||
by the servlet container. In Spring Security, the filter classes are also Spring beans defined in the application context and thus able
|
||||
to take advantage of Spring's rich dependency-injection facilities and lifecycle interfaces. Spring's <classname>DelegatingFilterProxy</classname>
|
||||
provides the link between <filename>web.xml</filename> and the application context.
|
||||
</para>
|
||||
<para>When using <classname>DelegatingFilterProxy</classname>, you will see something like this in the <filename>web.xml</filename> file:
|
||||
|
||||
<programlisting><![CDATA[
|
||||
<filter>
|
||||
<filter-name>myFilter</filter-name>
|
||||
@ -103,132 +38,111 @@
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>]]>
|
||||
</programlisting>
|
||||
|
||||
Notice that the filter is actually a <literal>DelegatingFilterProxy</literal>,
|
||||
and not the filter that will actually implement the logic of the filter. What
|
||||
<literal>DelegatingFilterProxy</literal> does is delegate the
|
||||
<literal>Filter</literal>'s methods through to a bean which is
|
||||
obtained from the Spring application context. This enables the bean to
|
||||
benefit from the Spring web application context lifecycle support and
|
||||
configuration flexibility. The bean must implement
|
||||
<literal>javax.servlet.Filter</literal> and it must have the same name as that in
|
||||
the <literal>filter-name</literal> element.</para>
|
||||
|
||||
<para>There is a lifecycle issue to consider when hosting
|
||||
<literal>Filter</literal>s in an IoC container instead of a servlet
|
||||
container. Specifically, which container should be responsible for
|
||||
calling the <literal>Filter</literal>'s "startup" and "shutdown"
|
||||
methods? It is noted that the order of initialization and destruction
|
||||
of a <literal>Filter</literal> can vary by servlet container, and this
|
||||
can cause problems if one <literal>Filter</literal> depends on
|
||||
configuration settings established by an earlier initialized
|
||||
<literal>Filter</literal>. The Spring IoC container on the other hand
|
||||
has more comprehensive lifecycle/IoC interfaces (such as
|
||||
<literal>InitializingBean</literal>,
|
||||
<literal>DisposableBean</literal>, <literal>BeanNameAware</literal>,
|
||||
<literal>ApplicationContextAware</literal> and many others) as well as
|
||||
a well-understood interface contract, predictable method invocation
|
||||
ordering, autowiring support, and even options to avoid implementing
|
||||
Spring interfaces (eg the <literal>destroy-method</literal> attribute
|
||||
in Spring XML). For this reason we recommend the use of Spring
|
||||
lifecycle services instead of servlet container lifecycle services
|
||||
wherever possible. Read the Javadoc for <classname>DelegatingFilterProxy</classname>
|
||||
for more information</para>
|
||||
|
||||
<para>Rather than using <literal>DelegatingFilterProxy</literal>, we
|
||||
strongly recommend that you use <classname>FilterChainProxy</classname> instead.
|
||||
Whilst <literal>DelegatingFilterProxy</literal> is a very useful class,
|
||||
the problem is that the number of lines of code required for
|
||||
<literal><filter></literal> and
|
||||
<literal><filter-mapping></literal> entries in
|
||||
<literal>web.xml</literal> explodes when using more than a few
|
||||
filters. To overcome this issue, Spring Security provides a
|
||||
<classname>FilterChainProxy</classname> class. It is wired using a
|
||||
<literal>DelegatingFilterProxy</literal> (just like in the example above),
|
||||
but the target class is
|
||||
<literal>org.springframework.security.web.FilterChainProxy</literal>.
|
||||
The filter chain is then declared in the application context, using
|
||||
code such as this:</para>
|
||||
|
||||
<para><programlisting><![CDATA[
|
||||
Notice that the filter is actually a <literal>DelegatingFilterProxy</literal>,
|
||||
and not the class that will actually implement the logic of the filter. What
|
||||
<classname>DelegatingFilterProxy</classname> does is delegate the
|
||||
<interfacename>Filter</interfacename>'s methods through to a bean which is
|
||||
obtained from the Spring application context. This enables the bean to
|
||||
benefit from the Spring web application context lifecycle support and
|
||||
configuration flexibility. The bean must implement
|
||||
<interfacename>javax.servlet.Filter</interfacename> and it must have the same name as that in
|
||||
the <literal>filter-name</literal> element. Read the Javadoc for <classname>DelegatingFilterProxy</classname>
|
||||
for more information</para>
|
||||
</section>
|
||||
<section xml:id="filter-chain-proxy">
|
||||
<title><classname>FilterChainProxy</classname></title>
|
||||
<para>
|
||||
It should now be clear that you can declare each Spring Security filter bean that you require in your application context file and add a corresponding
|
||||
<classname>DelegatingFilterProxy</classname> entry to <filename>web.xml</filename> for each filter, making sure that they are ordered correctly.
|
||||
This is a cumbersome approach and clutters up the <filename>web.xml</filename> file quickly if we have a lot of filters. We would prefer to just add
|
||||
a single entry to <filename>web.xml</filename> and deal entirely with the application context file for managing our web security beans.
|
||||
This is where Spring Secuiryt's <classname>FilterChainProxy</classname> comes in. It is wired using a <literal>DelegatingFilterProxy</literal>
|
||||
(just like in the example above), but the target class is <classname>org.springframework.security.web.FilterChainProxy</classname>.
|
||||
The filter chain is then declared in the application context. Here's an example:
|
||||
<programlisting language="xml"><![CDATA[
|
||||
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
|
||||
<sec:filter-chain-map path-type="ant">
|
||||
<sec:filter-chain pattern="/webServices/**" filters="
|
||||
httpSessionContextIntegrationFilterWithASCFalse,
|
||||
securityContextPersistenceFilterWithASCFalse,
|
||||
basicProcessingFilter,
|
||||
exceptionTranslationFilter,
|
||||
filterSecurityInterceptor" />
|
||||
<sec:filter-chain pattern="/**" filters="
|
||||
httpSessionContextIntegrationFilterWithASCTrue,
|
||||
securityContextPersistenceFilterWithASCTrue,
|
||||
authenticationProcessingFilter,
|
||||
exceptionTranslationFilter,
|
||||
filterSecurityInterceptor" />
|
||||
</sec:filter-chain-map>
|
||||
</bean>
|
||||
]]>
|
||||
</programlisting></para>
|
||||
|
||||
<para>You may notice similarities with the way
|
||||
<classname>FilterSecurityInterceptor</classname> is declared. Both regular
|
||||
expressions and Ant Paths are supported, and the most specific URIs
|
||||
appear first. At runtime the <classname>FilterChainProxy</classname> will
|
||||
locate the first URI pattern that matches the current web request and the list
|
||||
of filter beans specified by the <literal>filters</literal> attribute
|
||||
will be applied to that request. The filters will be invoked in the order
|
||||
they are defined, so you have complete control over the filter chain
|
||||
which is applied to a particular URL.</para>
|
||||
|
||||
<para>You may have noticed we have declared two
|
||||
<classname>HttpSessionContextIntegrationFilter</classname>s in the filter
|
||||
chain (<literal>ASC</literal> is short for
|
||||
<literal>allowSessionCreation</literal>, a property of
|
||||
<classname>HttpSessionContextIntegrationFilter</classname>). As web
|
||||
services will never present a <literal>jsessionid</literal> on future
|
||||
requests, creating <literal>HttpSession</literal>s for such user
|
||||
agents would be wasteful. If you had a high-volume application which
|
||||
required maximum scalability, we recommend you use the approach shown
|
||||
above. For smaller applications, using a single
|
||||
<classname>HttpSessionContextIntegrationFilter</classname> (with its
|
||||
default <literal>allowSessionCreation</literal> as
|
||||
<literal>true</literal>) would likely be sufficient.</para>
|
||||
|
||||
<para>In relation to lifecycle issues, the
|
||||
<classname>FilterChainProxy</classname> will always delegate
|
||||
<literal>init(FilterConfig)</literal> and <literal>destroy()</literal>
|
||||
methods through to the underlaying <literal>Filter</literal>s if such
|
||||
methods are called against <classname>FilterChainProxy</classname> itself.
|
||||
In this case, <classname>FilterChainProxy</classname> guarantees to only
|
||||
initialize and destroy each <literal>Filter</literal> once,
|
||||
irrespective of how many times it is declared by the
|
||||
<interfacename>FilterInvocationDefinitionSource</interfacename>. You control the
|
||||
overall choice as to whether these methods are called or not via the
|
||||
<literal>targetFilterLifecycle</literal> initialization parameter of the
|
||||
<literal>DelegatingFilterProxy</literal> that proxies
|
||||
<literal>DelegatingFilterProxy</literal>. As discussed above, by default
|
||||
any servlet container lifecycle invocations are not delegated through
|
||||
to <literal>DelegatingFilterProxy</literal>.</para>
|
||||
|
||||
<para>You can use the attribute <literal>filters = "none"</literal>
|
||||
in the same way that you do when using <link xlink:href="#namespace-auto-config">namespace configuration</link>
|
||||
to build the <classname>FilterChainProxy</classname>. This will omit the
|
||||
request pattern from the security filter chain entirely.
|
||||
Note that anything matching this path will then have
|
||||
no authentication or authorization services applied and will be freely
|
||||
accessible.</para>
|
||||
|
||||
<para>The order that filters are defined in <literal>web.xml</literal>
|
||||
</programlisting>
|
||||
The namespace element <literal>filter-chain-map</literal> is used to set up the security filter chain(s) which are required
|
||||
within the application. It maps a particular URL pattern to a chain of filters built up from the bean names
|
||||
specified in the <literal>filters</literal> element. Both regular
|
||||
expressions and Ant Paths are supported, and the most specific URIs
|
||||
appear first. At runtime the <classname>FilterChainProxy</classname> will
|
||||
locate the first URI pattern that matches the current web request and the list
|
||||
of filter beans specified by the <literal>filters</literal> attribute
|
||||
will be applied to that request. The filters will be invoked in the order
|
||||
they are defined, so you have complete control over the filter chain
|
||||
which is applied to a particular URL.</para>
|
||||
|
||||
<para>You may have noticed we have declared two
|
||||
<classname>SecurityContextPersistenceFilter</classname>s in the filter
|
||||
chain (<literal>ASC</literal> is short for
|
||||
<literal>allowSessionCreation</literal>, a property of
|
||||
<classname>SecurityContextPersistenceFilter</classname>). As web
|
||||
services will never present a <literal>jsessionid</literal> on future
|
||||
requests, creating <literal>HttpSession</literal>s for such user
|
||||
agents would be wasteful. If you had a high-volume application which
|
||||
required maximum scalability, we recommend you use the approach shown
|
||||
above. For smaller applications, using a single
|
||||
<classname>SecurityContextPersistenceFilter</classname> (with its
|
||||
default <literal>allowSessionCreation</literal> as
|
||||
<literal>true</literal>) would likely be sufficient.</para>
|
||||
|
||||
<para>In relation to lifecycle issues, the
|
||||
<classname>FilterChainProxy</classname> will always delegate
|
||||
<methodname>init(FilterConfig)</methodname> and <methodname>destroy()</methodname>
|
||||
methods through to the underlaying <interfacename>Filter</interfacename>s if such
|
||||
methods are called against <classname>FilterChainProxy</classname> itself.
|
||||
In this case, <classname>FilterChainProxy</classname> guarantees to only
|
||||
initialize and destroy each <literal>Filter</literal> bean once,
|
||||
no matter how many times it is declared in the filter chain(s). You control the
|
||||
overall choice as to whether these methods are called or not via the
|
||||
<literal>targetFilterLifecycle</literal> initialization parameter of
|
||||
<literal>DelegatingFilterProxy</literal>. By default this property
|
||||
is <literal>false</literal> and servlet container lifecycle invocations are not delegated through
|
||||
<literal>DelegatingFilterProxy</literal>.</para>
|
||||
<para>
|
||||
When we looked at how to set up web security using <link xlink:href="#namespace-auto-config">namespace configuration</link>,
|
||||
we used a <literal>DelegatingFilterProxy</literal> with the name <quote>springSecurityFilterChain</quote>. You should now be able to
|
||||
see that this is the name of the <classname>FilterChainProxy</classname> which is created by the namespace.
|
||||
</para>
|
||||
<section>
|
||||
<title>Bypassing the Filter Chain</title>
|
||||
<para>
|
||||
As with the namespace, you can use the attribute <literal>filters = "none"</literal> as an alternative to supplying a filter bean list.
|
||||
This will omit the request pattern from the security filter chain entirely. Note that anything matching this path will then have
|
||||
no authentication or authorization services applied and will be freely accessible.
|
||||
</para>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Filter Ordering</title>
|
||||
<para>The order that filters are defined in the chain
|
||||
is very important. Irrespective of which filters you are actually
|
||||
using, the order of the <literal><filter-mapping></literal>s
|
||||
should be as follows:</para>
|
||||
using, the order should be as follows:
|
||||
|
||||
<orderedlist inheritnum="ignore" continuation="restarts">
|
||||
<listitem>
|
||||
<para><literal>ChannelProcessingFilter</literal>, because it might
|
||||
<para><classname>ChannelProcessingFilter</classname>, because it might
|
||||
need to redirect to a different protocol</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>ConcurrentSessionFilter</literal>, because it
|
||||
<para><classname>ConcurrentSessionFilter</classname>, because it
|
||||
doesn't use any <classname>SecurityContextHolder</classname>
|
||||
functionality but needs to update the
|
||||
<interfacename>SessionRegistry</interfacename> to reflect ongoing requests
|
||||
@ -236,7 +150,7 @@
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><classname>HttpSessionContextIntegrationFilter</classname>, so a
|
||||
<para><classname>SecurityContextPersistenceFilter</classname>, so a
|
||||
<interfacename>SecurityContext</interfacename> can be setup in the
|
||||
<classname>SecurityContextHolder</classname> at the beginning of a web
|
||||
request, and any changes to the <interfacename>SecurityContext</interfacename>
|
||||
@ -246,10 +160,9 @@
|
||||
|
||||
<listitem>
|
||||
<para>Authentication processing mechanisms -
|
||||
<literal>UsernamePasswordAuthenticationProcessingFilter</literal>,
|
||||
<literal>CasProcessingFilter</literal>,
|
||||
<literal>BasicProcessingFilter, HttpRequestIntegrationFilter,
|
||||
JbossIntegrationFilter</literal> etc - so that the
|
||||
<classname>UsernamePasswordAuthenticationProcessingFilter</classname>,
|
||||
<classname>CasProcessingFilter</classname>,
|
||||
<classname>BasicProcessingFilter</classname> etc - so that the
|
||||
<classname>SecurityContextHolder</classname> can be modified to
|
||||
contain a valid <interfacename>Authentication</interfacename> request
|
||||
token</para>
|
||||
@ -274,7 +187,7 @@
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para><literal>AnonymousProcessingFilter</literal>, so that if no
|
||||
<para><classname>AnonymousProcessingFilter</classname>, so that if no
|
||||
earlier authentication processing mechanism updated the
|
||||
<classname>SecurityContextHolder</classname>, an anonymous
|
||||
<interfacename>Authentication</interfacename> object will be put there</para>
|
||||
@ -292,21 +205,20 @@
|
||||
URIs</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
<para>All of the above filters use
|
||||
<literal>DelegatingFilterProxy</literal> or
|
||||
<classname>FilterChainProxy</classname>. It is recommended that a single
|
||||
<literal>DelegatingFilterProxy</literal> proxy through to a single
|
||||
<classname>FilterChainProxy</classname> for each application, with that
|
||||
<classname>FilterChainProxy</classname> defining all of Spring Security
|
||||
filters.</para>
|
||||
|
||||
<para>If you're using SiteMesh, ensure Spring Security filters execute
|
||||
before the SiteMesh filters are called. This enables the
|
||||
<classname>SecurityContextHolder</classname> to be populated in time for
|
||||
use by SiteMesh decorators</para>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Use with other Filter-Based Frameworks</title>
|
||||
<para>If you're using SiteMesh, ensure Spring Security filters execute
|
||||
before the SiteMesh filters are called. This enables the
|
||||
<classname>SecurityContextHolder</classname> to be populated in time for
|
||||
use by SiteMesh decorators.</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</section>
|
||||
<section xml:id="taglib">
|
||||
<info><title>Tag Libraries</title></info>
|
||||
|
||||
|
@ -580,4 +580,67 @@ Successfully authenticated. Security context contains: \
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section xml:id="localization">
|
||||
<title>Localization</title>
|
||||
<para>Spring Security supports localization of exception messages that
|
||||
end users are likely to see. If your application is designed for
|
||||
English-speaking users, you don't need to do 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>
|
||||
|
||||
<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>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[
|
||||
<bean id="messageSource"
|
||||
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
|
||||
<property name="basename" value="org/springframework/security/messages"/>
|
||||
</bean>
|
||||
]]></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>
|
||||
|
||||
<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 file, so localization should not be
|
||||
considered a major initiative. If you do perform 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>
|
||||
</section>
|
||||
</chapter>
|
||||
|
Loading…
x
Reference in New Issue
Block a user