Spring security guest user

Viewed 3156

I have a custom UserDetails implementation that has a shopping cart property.

class MyUserDetails implement UserDetails {
    private Cart cart;
    // getters & setters + other properties....
}

I want anonymous users to be a instance of MyUserDetails too, so far I have gotten it working otherwise, but all anonymousUsers have the same shopping cart!

@Override
protected void configure(HttpSecurity http) throws Exception {
    MyUserDetails anonymousUser = new MyUserDetails();
    anonymousUser.setUsername("anonymousUser");
    http.anonymous().principal(anonymousUser);
    ...
}

How would I be able to return a new instance of MyUserDetails for anonymous users for each session?

2 Answers

I am pretty sure I managed to get it working by creating a custom AnonymousAuthenticationFilter like this:

public class MyAnonymousAuthenticationFilter extends AnonymousAuthenticationFilter {
    private static final String USER_SESSION_KEY = "user";
    private final String key;

    public MyAnonymousAuthenticationFilter(String key) {
        super(key);
        this.key = key;
    }

    @Override
    protected Authentication createAuthentication(HttpServletRequest req) {
        HttpSession httpSession = req.getSession();
        MyUserDetails user = Optional.ofNullable((MyUserDetails) httpSession.getAttribute(USER_SESSION_KEY))
                .orElseGet(() -> {
                    MyUserDetails anon = new MyUserDetails();
                    anon.setUsername("anonymousUser");
                    httpSession.setAttribute(USER_SESSION_KEY, anon);
                    return anon;
                });
        return new AnonymousAuthenticationToken(key, user, AuthorityUtils.createAuthorityList("ROLE_ANONYMOUS"));
    }
}

and then use it with http.anonymous().authenticationFilter(new MyAnonymousAuthenticationFilter(UUID.randomUUID().toString()));

If there is something wrong with this approach, or if you know a better way, please let me know!

My first remark is that I tend to agree with the comments of @dur but that's another story :-)

If you still prefer to stick to your approach then I think it would be more inline with Spring architecture if instead of a filter you Implement your own AuthenticationProvider which is able to process (authenticate) anonymous tokens. Like this:

public class MyAuthenticationProvider implements AuthenticationProvider {

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {

    //enrich the authentication here.
  }


  @Override
  public boolean supports(Class<?> authentication) {
    return (AnonymousAuthenticationToken.class
        .isAssignableFrom(authentication));
  }
}

You will then register this provider in your filter chain which might be initialized by a WebSecurityConfigurerAdapter, for example. You will do this by configuring the local authentication manager. This will look somehow like this:

@Override
protected void configure(
    AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(new MyAuthenticationProvider());
}

For an excellent in-depth review of the spring security architecture please see here.

Related