Spring Security(二十一):6.3 Advanced Web Features
6.3.1 Remember-Me Authentication (记住我的身份验证)
See the separate Remember-Me chapter for information on remember-me namespace configuration.
6.3.2 Adding HTTP/HTTPS Channel Security(添加HTTP / HTTPS通道安全性)
If your application supports both HTTP and HTTPS, and you require that particular URLs can only be accessed over HTTPS, then this is directly supported using the requires-channel
attribute on <intercept-url>
:
<http> <intercept-url pattern="/secure/**" access="ROLE_USER" requires-channel="https"/> <intercept-url pattern="/**" access="ROLE_USER" requires-channel="any"/> ... </http>
With this configuration in place, if a user attempts to access anything matching the "/secure/**" pattern using HTTP, they will first be redirected to an HTTPS URL [5]. The available options are "http", "https" or "any". Using the value "any" means that either HTTP or HTTPS can be used.
<http> ... <port-mappings> <port-mapping http="9080" https="9443"/> </port-mappings> </http>
Note that in order to be truly secure, an application should not use HTTP at all or switch between HTTP and HTTPS. It should start in HTTPS (with the user entering an HTTPS URL) and use a secure connection throughout to avoid any possibility of man-in-the-middle attacks.
6.3.3 Session Management
Detecting Timeouts(检测超时)
You can configure Spring Security to detect the submission of an invalid session ID and redirect the user to an appropriate URL. This is achieved through the session-management
element:
<http> ... <session-management invalid-session-url="/invalidSession.htm" /> </http>
Note that if you use this mechanism to detect session timeouts, it may falsely report an error if the user logs out and then logs back in without closing the browser. This is because the session cookie is not cleared when you invalidate the session and will be resubmitted even if the user has logged out. You may be able to explicitly delete the JSESSIONID cookie on logging out, for example by using the following syntax in the logout handler:
<http> <logout delete-cookies="JSESSIONID" /> </http>
Unfortunately this can’t be guaranteed to work with every servlet container, so you will need to test it in your environment
JSESSIONID
cookie by expiring it in the response to a logout request (assuming the application is deployed under the path /tutorial
):<LocationMatch "/tutorial/logout"> Header always set Set-Cookie "JSESSIONID=;Path=/tutorial;Expires=Thu, 01 Jan 1970 00:00:00 GMT" </LocationMatch>
Concurrent Session Control
If you wish to place constraints on a single user’s ability to log in to your application, Spring Security supports this out of the box with the following simple additions. First you need to add the following listener to your web.xml
file to keep Spring Security updated about session lifecycle events:
<http> ... <session-management> <concurrency-control max-sessions="1" /> </session-management> </http>
This will prevent a user from logging in multiple times - a second login will cause the first to be invalidated. Often you would prefer to prevent a second login, in which case you can use
<http> ... <session-management> <concurrency-control max-sessions="1" error-if-maximum-exceeded="true" /> </session-management> </http>
The second login will then be rejected. By "rejected", we mean that the user will be sent to the authentication-failure-url
if form-based login is being used. If the second authentication takes place through another non-interactive mechanism, such as "remember-me", an "unauthorized" (401) error will be sent to the client. If instead you want to use an error page, you can add the attribute session-authentication-error-url
to the session-management
element.
Session Fixation Attack Protection(会话固定攻击保护)
Session fixation attacks are a potential risk where it is possible for a malicious attacker to create a session by accessing a site, then persuade another user to log in with the same session (by sending them a link containing the session identifier as a parameter, for example). Spring Security protects against this automatically by creating a new session or otherwise changing the session ID when a user logs in. If you don’t require this protection, or it conflicts with some other requirement, you can control the behavior using the session-fixation-protection
attribute on <session-management>
, which has four options
none
- Don’t do anything. The original session will be retained.-
什么都不做原始会话将保留。
newSession
- Create a new "clean" session, without copying the existing session data (Spring Security-related attributes will still be copied).-
创建一个新的“干净”会话,而不复制现有的会话数据(仍将复制与Spring Security相关的属性)。
migrateSession
- Create a new session and copy all existing session attributes to the new session. This is the default in Servlet 3.0 or older containers.-
创建新会话并将所有现有会话属性复制到新会话。这是Servlet 3.0或旧容器中的默认设置。
changeSessionId
- Do not create a new session. Instead, use the session fixation protection provided by the Servlet container (HttpServletRequest#changeSessionId()
). This option is only available in Servlet 3.1 (Java EE 7) and newer containers. Specifying it in older containers will result in an exception. This is the default in Servlet 3.1 and newer containers.-
不要创建新会话。而是使用Servlet容器提供的会话固定保护(HttpServletRequest#changeSessionId())。此选项仅适用于Servlet 3.1(Java EE 7)和更新的容器。在旧容器中指定它将导致异常。这是Servlet 3.1和更新容器中的默认设置。
When session fixation protection occurs, it results in a SessionFixationProtectionEvent
being published in the application context. If you use changeSessionId
, this protection will also result in any javax.servlet.http.HttpSessionIdListener
s being notified, so use caution if your code listens for both events. See the Session Management chapter for additional information.
6.3.4 OpenID Support
The namespace supports OpenID login either instead of, or in addition to normal form-based login, with a simple change:
<http> <intercept-url pattern="/**" access="ROLE_USER" /> <openid-login /> </http>
You should then register yourself with an OpenID provider (such as myopenid.com), and add the user information to your in-memory <user-service>
:
<user name="http://jimi.hendrix.myopenid.com/" authorities="ROLE_USER" />
You should be able to login using the myopenid.com
site to authenticate. It is also possible to select a specific UserDetailsService
bean for use OpenID by setting the user-service-ref
attribute on the openid-login
element. See the previous section on authentication providers for more information. Note that we have omitted the password attribute from the above user configuration, since this set of user data is only being used to load the authorities for the user. A random password will be generated internally, preventing you from accidentally using this user data as an authentication source elsewhere in your configuration.
Attribute Exchange(属性交换)
Support for OpenID attribute exchange. As an example, the following configuration would attempt to retrieve the email and full name from the OpenID provider, for use by the application:
<openid-login> <attribute-exchange> <openid-attribute name="email" type="http://axschema.org/contact/email" required="true"/> <openid-attribute name="name" type="http://axschema.org/namePerson"/> </attribute-exchange> </openid-login>
The "type" of each OpenID attribute is a URI, determined by a particular schema, in this case http://axschema.org/. If an attribute must be retrieved for successful authentication, the required
attribute can be set. The exact schema and attributes supported will depend on your OpenID provider. The attribute values are returned as part of the authentication process and can be accessed afterwards using the following code:
OpenIDAuthenticationToken token = (OpenIDAuthenticationToken)SecurityContextHolder.getContext().getAuthentication(); List<OpenIDAttribute> attributes = token.getAttributes();
The OpenIDAttribute
contains the attribute type and the retrieved value (or values in the case of multi-valued attributes). We’ll see more about how the SecurityContextHolder
class is used when we look at core Spring Security components in the technical overview chapter. Multiple attribute exchange configurations are also be supported, if you wish to use multiple identity providers. You can supply multiple attribute-exchange
elements, using an identifier-matcher
attribute on each. This contains a regular expression which will be matched against the OpenID identifier supplied by the user. See the OpenID sample application in the codebase for an example configuration, providing different attribute lists for the Google, Yahoo and MyOpenID providers.
6.3.5 Response Headers
For additional information on how to customize the headers element refer to the Chapter 20, Security HTTP Response Headers section of the reference.
6.3.6 Adding in Your Own Filters(添加自己的过滤器)
If you’ve used Spring Security before, you’ll know that the framework maintains a chain of filters in order to apply its services. You may want to add your own filters to the stack at particular locations or use a Spring Security filter for which there isn’t currently a namespace configuration option (CAS, for example). Or you might want to use a customized version of a standard namespace filter, such as the UsernamePasswordAuthenticationFilter
which is created by the <form-login>
element, taking advantage of some of the extra configuration options which are available by using the bean explicitly. How can you do this with namespace configuration, since the filter chain is not directly exposed?
<http>
element, so the syntax has changed slightly in 3.0.Alias | Filter Class | Namespace Element or Attribute |
---|---|---|
CHANNEL_FILTER |
|
|
SECURITY_CONTEXT_FILTER |
|
|
CONCURRENT_SESSION_FILTER |
|
|
HEADERS_FILTER |
|
|
CSRF_FILTER |
|
|
LOGOUT_FILTER |
|
|
X509_FILTER |
|
|
PRE_AUTH_FILTER |
|
N/A |
CAS_FILTER |
|
N/A |
FORM_LOGIN_FILTER |
|
|
BASIC_AUTH_FILTER |
|
|
SERVLET_API_SUPPORT_FILTER |
|
|
JAAS_API_SUPPORT_FILTER |
|
|
REMEMBER_ME_FILTER |
|
|
ANONYMOUS_FILTER |
|
|
SESSION_MANAGEMENT_FILTER |
|
|
EXCEPTION_TRANSLATION_FILTER |
|
|
FILTER_SECURITY_INTERCEPTOR |
|
|
SWITCH_USER_FILTER |
|
N/A |
custom-filter
element and one of these names to specify the position your filter should appear at:<http> <custom-filter position="FORM_LOGIN_FILTER" ref="myFilter" /> </http> <beans:bean id="myFilter" class="com.mycompany.MySpecialAuthenticationFilter"/>
You can also use the after
or before
attributes if you want your filter to be inserted before or after another filter in the stack. The names "FIRST" and "LAST" can be used with the position
attribute to indicate that you want your filter to appear before or after the entire stack, respectively.
If you are inserting a custom filter which may occupy the same position as one of the standard filters created by the namespace then it’s important that you don’t include the namespace versions by mistake. Remove any elements which create filters whose functionality you want to replace.
Note that you can’t replace filters which are created by the use of the <http>
element itself - SecurityContextPersistenceFilter
, ExceptionTranslationFilter
or FilterSecurityInterceptor
. Some other filters are added by default, but you can disable them. An AnonymousAuthenticationFilter
is added by default and unless you have session-fixation protection disabled, a SessionManagementFilter
will also be added to the filter chain.
Setting a Custom AuthenticationEntryPoint(设置自定义AuthenticationEntryPoint)
If you aren’t using form login, OpenID or basic authentication through the namespace, you may want to define an authentication filter and entry point using a traditional bean syntax and link them into the namespace, as we’ve just seen. The corresponding AuthenticationEntryPoint
can be set using the entry-point-ref
attribute on the <http>
element.