1

In JSP I can get username by ${pageContext.request.remoteUser}. But there is also additional info (rating of user) I need to display on every page of my site. How can I access it, considering there is a @Service to get it by username?

For what it's worth I use custom authentication provider:

@Service
public class MyUserDetailsService implements UserDetailsService {
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return new User(s, "password", Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
    }
}
<security:authentication-manager>
    <security:authentication-provider user-service-ref='myUserDetailsService'/>
</security:authentication-manager>
dur
  • 15,689
  • 25
  • 79
  • 125
Nelson Tatius
  • 7,693
  • 8
  • 47
  • 70

2 Answers2

3

You could create implementation of AuthenticationSuccessHandler and set an attribute there:

@Component
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
    Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
        request.getSession().setAttribute("someDetail", "detailsValue");
        response.sendRedirect("/to-whatever-url-you-want")
    }
}

Upon successful login, someDetail attribute will be set. Note that you can also obtain currently logged in user from Authentication instance and perform some logic.

Branislav Lazic
  • 14,388
  • 8
  • 60
  • 85
  • 2
    For future readers. It's also important to register `AuthenticationSuccessHandlerImpl` as a login form handler. ` ` – Nelson Tatius Mar 04 '17 at 16:07
  • 1
    @Jofsey Yup. In case of annotation configuration, in `WebSecurityConfigurerAdapter` impl. class you can add it like this: `http.formLogin().loginPage("/login").failureUrl("/login?error").successHandler(new AuthenticationSuccessHandlerImpl())` – Branislav Lazic Mar 04 '17 at 16:09
3

You can create a custom UserDetails class (e.g. MyUserDetails) and save the extra information there. In your UserDetailsService, just return this MyUserDetails instead of the normal UserDetail.

public class MyUserDetails extends UserDetail {
    private int rating;
    ... // other properties
    ... // getter setter
}

@Service
public class MyUserDetailsService implements UserDetailsService {
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return new MyUserDetails(...);
    }
}

In every controller, you can call

(MyUserDetails)SecurityContextHolder.getContext().getAuthentication().getPrincipal();

to the get the current principal/UserDetails, which contains your extra info(e.g. rating of the user).

P.s. If this extra info is related to users, sessions are not the right place to store it, because sessions may expire after closing the browser. If this extra info is just some temporary data, then @Branislav Lazic's answer is correct. Since I can't add a comment, so I have to write the comments to @Branislav Lazic's answer here.

Simon
  • 629
  • 3
  • 8
  • I don't see an issue in question whether that's some temporary data or not. If session expires, user will simply be redirected to login page to renew his session and therefore, it will reset additional user attribute. Storing that attribute within the whole application context could be dangerous as hell! – Branislav Lazic Mar 04 '17 at 23:24
  • 1
    @BranislavLazic from my understanding, something like the rating of user could be persisted in the database as a property of the user. It is anyway loaded within the `loadUserByUsername` function. If it is set during the session, that means it may be different in different sessions, that is what I mean for temporary. In this case, of course it should be stored in the session, since it is a property of the user session. Besides, redirecting back to login page and auto login usually relies a persistent cookie. If an application doesn't offer that, this can not be achieved this way. – Simon Mar 05 '17 at 02:46
  • 1
    Even if you can automatically restore the session, then the additional attribute is also in the so called "application context", because you can retrieve it any time. The SecurityContext is usually set to the threadLocal, if it is configured, it will also be saved in the HttpSession. IMHO, it can only be more secure. Maybe checkout this http://stackoverflow.com/questions/6408007/spring-securitys-securitycontextholder-session-or-request-bound for some explanation. Anyways, this is what Spring Security offers you to use, why not simply use it – Simon Mar 05 '17 at 02:51