Spring Security(Third Edition)
上QQ阅读APP看书,第一时间看更新

Logging in a new user to an application

Now that we are able to add new users to the system, we need to indicate that the user is authenticated. Update SpringSecurityUserContext to set the current user on the SecurityContextHolder object of Spring Security, as follows:

    //src/main/java/com/packtpub/springsecurity/service/
SpringSecurityUserContext.java

public void setCurrentUser(CalendarUser user) {
UserDetails userDetails = userDetailsService.
loadUserByUsername(user.getEmail());
Authentication authentication = new
UsernamePasswordAuthenticationToken(userDetails, user.getPassword(),
userDetails.getAuthorities());
SecurityContextHolder.getContext().
setAuthentication(authentication);
}

The first step we perform is to convert our CalendarUser object into the UserDetails object of Spring Security. This is necessary because, just as Spring Security didn't know how to save our custom CalendarUser object, Spring Security also does not understand how to make security decisions with our custom CalendarUser object. We use Spring Security's o.s.s.core.userdetails.UserDetailsService interface to obtain the same UserDetails object we saved with UserDetailsManager. The UserDetailsService interface provides a subset, lookup by username, of the functionality provided by Spring Security's UserDetailsManager object that we have already seen.

Next, we create a UsernamePasswordAuthenticationToken object and place UserDetails, the password, and GrantedAuthority in it. Lastly, we set the authentication on SecurityContextHolder. In a web application, Spring Security will automatically associate the SecurityContext object in SecurityContextHolder to our HTTP session for us.

It is important that Spring Security must not be instructed to ignore a URL (that is, using the permitAll() method), as discussed in Chapter 2, Getting Started with Spring Security, in which SecurityContextHolder is accessed or set. This is because Spring Security will ignore the request and thus not persist SecurityContext for subsequent requests. The proper method to allow access to the URL in which SecurityContextHolder is used is to specify the access attribute of the antMatchers() method (that is, antMatchers(…).permitAll()).

It is worth mentioning that we could have converted CalendarUser by creating a new o.s.s.core.userdetails.User object directly, instead of looking it up in UserDetailsService. For example, the following code would also authenticate the user:

List<GrantedAuthority> authorities =
AuthorityUtils.createAuthorityList("ROLE_USER");
UserDetails userDetails = new User("username","password",authorities);
Authentication authentication = new UsernamePasswordAuthenticationToken ( userDetails,userDetails.getPassword(),userDetails.getAuthorities());
SecurityContextHolder.getContext()
.setAuthentication(authentication);

The advantage of this approach is that there is no need to hit the datastore again. In our case, the datastore is an in-memory datastore, but this could be backed by a database, which could have some security implications. The disadvantage of this approach is that we do not get to reuse the code much. Since this method is invoked infrequently, we opt for reusing the code. In general, it is best to evaluate each situation separately to determine which approach makes the most sense.