角弓反张和打挺图片:自定义 AuthenticationProcessingFilter-1

来源:百度文库 编辑:九乡新闻网 时间:2024/10/06 00:22:59

Custom AuthenticationProcessingFilter for spring security to perform actions on login

February 16th, 2009 | Tags: Spring, spring security, web security

Question like this onepopup on the spring security forum all the time. The question is almostalways the same. The system must perform some custom action after auser logs in or out of the system. And almost always this action has tobe performed on the session like setting an attribute or removing one.Sometimes user’s also want to put their own User object in the sessionfor later use in the application. All these actions can be performed bywriting a custom AuthenticationProcessingFilter and replacing thedefault instance on the filter chain with your implementation.

Before I show you how to write your very own filter,let me just say that you don’t necessarily need to do all this workjust to put your user’s details in the session. You can instead write acustom UserDetailsService which returns an extended User object (or your own implementation of UserDetails) which contains your user details. I have written an article showing you how to do the same.

Now onto our filter. First the implementation :

1 2 3 4 5 6 7 8 9 10 public class MyAuthenticationProcessingFilter extends AuthenticationProcessingFilter {       @Override     protected void onSuccessfulAuthentication(HttpServletRequest request,             HttpServletResponse response, Authentication authResult)             throws IOException {         super.onSuccessfulAuthentication(request, response, authResult);         request.getSession().setAttribute("myValue", "My value is set");     } }

Our filter simply sets a session attribute after a user successfully logs into the system.

This filter now needs to be plugged in. If you haven’t yet read the section on adding your own filters to spring security,I seriously suggest that you do, we’re going to use the informationprovided there to make spring security use our filter instead of thedefault one. To plug this filter in the following goes into yoursecurity-applicationContext.xml :

1 2 3 4 5 <bean id="authenticationProcessingFilter" class="com.codercorp.security.MyAuthenticationProcessingFilter">         <security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />         <property name="defaultTargetUrl" value="/main.html" />         <property name="authenticationManager" ref="authenticationManager" /> bean>

You also need to define an AuthenticationProcessingFilterEntryPoint since we’re going to break the default filter chain.


And configure an AuthenticationManager as well :

1 <security:authentication-manager alias="authenticationManager" />

Your security-applicationContext.xml should look something like this :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <security:global-method-security />   <security:http auto-config="false" entry-point-ref="authenticationProcessingFilterEntryPoint">     <security:intercept-url pattern="/index.jsp" filters="none" />     <security:intercept-url pattern="/**" access="ROLE_USER" /> security:http>   <security:authentication-provider user-service-ref="customUserDetailsService" />   <bean id="customUserDetailsService" class="com.codercorp.security.CustomUserDetailsService" />   <bean id="authenticationProcessingFilter" class="com.codercorp.security.MyAuthenticationProcessingFilter">     <security:custom-filter position="AUTHENTICATION_PROCESSING_FILTER" />     <property name="defaultTargetUrl" value="/main.html" />     <property name="authenticationManager" ref="authenticationManager" /> bean>   <security:authentication-manager alias="authenticationManager" />   <bean id="authenticationProcessingFilterEntryPoint" class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">     <property name="loginFormUrl" value="/index.jsp" />     <property name="forceHttps" value="false" /> bean>

Remember to switch off auto configuration of spring security bysetting auto-config property of the http element to false. If you don’tyou’ll get an exception :

1 Caused by: org.springframework.security.config.SecurityConfigurationException: Filters 'com.codercorp.security.MyAuthenticationProcessingFilter[ order=700; ]' and 'org.springframework.security.ui.webapp.AuthenticationProcessingFilter[ order=700; ]' have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the corresponding child elements from and avoiding the use of 'true'>.

Your custom AuthenticationProcessingFilter is now ready for use and you can perform actions whenever a user logs in.

Share and Enjoy:

No related posts.

Leave a comment| Trackback
  1. mononoke February 18th, 2009 at 20:04 Reply | Quote | #1

    Thanks for that. Uou should add in the article to add entry-point-ref=”authenticationProcessingFilterEntryPoint” to the part, otherwise I couldn’t get it to work.

    • Gaurav Arora February 19th, 2009 at 11:04 Reply | Quote | #2

      @mononoke:
      Thanks for that info, I forgot to copy the new config once I had changed it. Unless entry-point-ref is added, the example will not work.

      Gaurav

  2. dan February 20th, 2009 at 02:32 Reply | Quote | #3

    Thank you for your post. Very helpful.

  3. Beko February 27th, 2009 at 14:43 Reply | Quote | #4

    Hi all and thanks for helpful post.
    i am little bit confused about session management.when i added request.getSession().setAttribute(“myValue”, “My value is set”); line my sessionlistener destroyed that session and creates a new one after redirecting to defaultTargetUrl.

    i read your other post which is about user tracking already and tried to mix these but no success.

    #AuthenticationProcessfilter
    super.onSuccessfulAuthentication(request, response, authResult);
    UserDetail userDetail = (UserDetail)authResult.getPrincipal();
    request.getSession().setAttribute(“USER_DETAIL”, userDetail);
    UserTracker.getInstance().addUser(userDetail);

    #HttpSessionListener
    public void sessionDestroyed(HttpSessionEvent sessionEvent) {
    String sessionId = sessionEvent.getSession().getId();
    UserTracker.getInstance().removeUser(sessionId);
    }

    #UserTracker
    public synchronized void addUser(UserDetail userDetail){
    loggedUsers.put(userDetail.getSessionId(),userDetail);
    }

    public synchronized void removeUser(String sessionId){
    loggedUsers.remove(sessionId);
    }

  4. Beko February 27th, 2009 at 15:28 Reply | Quote | #5

    hell yes i found it.
    that s about session fixation attack.for detailed solution http://static.springsource.org/spring-security/site/reference/html/ns-config.html#ns-entry-point-ref

    thanks.

    • Gaurav Arora February 27th, 2009 at 15:34 Reply | Quote | #6

      Glad you found it, was about to say that you should use the migrateSession option to have best of both worlds.

  5. Malte March 9th, 2009 at 20:35 Reply | Quote | #7

    Thanks for your hints. They saved me a lot of time…

  6. Jussi March 23rd, 2009 at 16:04 Reply | Quote | #8

    Any pointers on how to performs custom actions when the user logs out?

    Implementing a standard HttpSessionListener might do the trick in most cases (although the Spring integration is quite clumsy) but session scoped beans are causing me problems. Everything works fine when user actually clicks the logout link but if the session times out I get a BeanCreationException from the session scoped beans.

    • Gaurav Arora March 24th, 2009 at 18:25 Reply | Quote | #9

      Thats a very known problem. I’d suggest you simply catch the BeanCreationException and ignore it. The only time the exception can occur is when spring is not managing your logout and that can only happen when the session times out.

  7. Jalpesh Patadia May 4th, 2009 at 23:35 Reply | Quote | #10

    Hello Gaurav,

    Thanks for this article. It certainly helps to resolve one issue I’m having.

    What I now need is a way to have multiple elements in my web site. One which uses the auto-config=true (standard form based auth), and one which uses a custom element for RESTful access, with it’s own AuthEntryPoint.

    I can easily create two filter-mappings in web.xml, but I have two problems :

    a) Spring security (2.0.4) does not allow multiple http elements in your applicationContext files.
    b) Most of the beans in my application are going to be shared with both the access points in my site (form based and REST based)

    I’ve searched around, but haven’t found any examples on getting this resolved.

    Would you have any suggestions on how would I go about doing that ?

    Thanks,

    Jalpesh.

  8. SDB June 1st, 2009 at 23:06 Reply | Quote | #11

    Hello Gaurav,

    Thanks for the post.
    I have a requirement. After successful login the user is taken to the welcome page. From there he can click on a link to navigate to another page. In the second page, I need to display some details regarding the user logged in. So my requirement is, when the user clicks the link in Welcome page, it should be taken to the controller where there will be come calculations and store the value in a session variable. When the page is rendered, then the value is to be displayed .So my doubt is how we can access the session variable in Controller java classes. Or is there any other way to attain this functionality.

    Please give me some pointers. I am new to spring. My application is using struts 2, spring, spring security and hibernate

    Thanks,
    SDB

    • Gaurav Arora June 2nd, 2009 at 19:20 Reply | Quote | #12

      You can access the session from the request..

  9. Dario June 12th, 2009 at 01:13 Reply | Quote | #13

    Hi! thanks for this very usefull tutorial. Anyway reading it, when you say

    “you don’t necessarily need to do all this work just to put your user’s details in the session. You can instead write a custom UserDetailsService which returns an extended User object (or your own implementation of UserDetails) which contains your user details.”

    I followed the article and I implemented my UserDetailsService, but now How do I get user details from the session? I mean, in a JSP page how do I get for example the user email? because for the username I can do

    But because the object “Principal” has a method called .getName()
    How can I do a similar thing with other user details?

    Many thanks in advance for the answer
    Dario

  10. Dario June 12th, 2009 at 01:16 Reply | Quote | #14

    the previus post didn’t show the following line
    ” ”

    after “because for the username I can do ”
    And before “But because the object ”
    Sorry for the mess..

  11. sunny August 13th, 2009 at 22:44 Reply | Quote | #15

    I have customized AuthenticationProcessingFilter for custom authentication. All working fine except, upon the unsuccess authentication, I like to display a custom message. So I am throwing BadCredentialExecption with the custom message. Upong the unsucessfull attempt, it never takes to the login page and never displays custom message. I see all the stacktrace on the page. URL shows j_spring_security_check.

    Any idea pls? I appreciate it

    @Override
    protected void onUnsuccessfulAuthentication(HttpServletRequest request,
    HttpServletResponse response, AuthenticationException failed) throws AuthenticationException, IOException
    {
    throw new BadCredentialsException(“Log In information not valid: Please enter a valid Username and associated Password.”);
    }

    • Gaurav Arora August 18th, 2009 at 10:58 Reply | Quote | #16

      Read this link on an idea of how to handle exceptions globally. This is possibly the easiest way to do it.

  12. Fuz September 3rd, 2009 at 00:34 Reply | Quote | #17

    Great stuff!
    everything almost works! but look at this:

    here you wrote filters=”none”. if you replace this with access=”IS_AUTHENTICATED_ANONYMOUSLY” browser goes to unstoppable redirecting. do you know what is it?
    Also spring security error handling dissapeared – server HTTP Status 401 error page now appears.

    • Andi September 21st, 2009 at 15:46 Reply | Quote | #18

      Hi!
      I have the same problem. It works only for filters=”none”, but then the redirect to https (reqires-channel=”https”) doesn’t work… Any idea?

  13. NaiveGeek April 2nd, 2010 at 03:21 Reply | Quote | #19

    Hey Gurav,
    Thanks for the info posted. It explained lot clearly and helped me successfully accomplish my task
    Naive Geek