Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Security @AuthenticationPrincipal

Tags:

I've been trying to get @AuthenticationPrincipal to work properly with a custom User class. Unfortunately, the user is always null. Here's the code:

Controller

@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(@AuthenticationPrincipal User user) {
    ModelAndView mav= new ModelAndView("/web/index");
    mav.addObject("user", user);
    return mav;
}

Security Config

@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    CustomUserDetailsService customUserDetailsService;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
    }

}

CustomUserDetailsService

@Component
public class CustomUserDetailsService implements UserDetailsService {

@Autowired
UserRepository userRepository;

@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    // Spring Data findByXY function
    return userRepository.findByUsername(username);
}

User Entity

public class User implements UserDetails{
    private String username;
    private String password;
    private Collection<Authority> authorities;

    // Getters and Setters

}

Authority Entity

public class Authority implements GrantedAuthority{
    private User user;
    private String role;

    // Getters and Setters

    @Override
    public String getAuthority() {
        return this.getRole();
    }
}

I've tried various solutions to this I found online, e.g. converting my custom user object like this:

return new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), true, true, true, true,  authorities);

The other ways to get the active users are working without a problem, but I find the @AuthenticationProvider CustomUserObject to be the cleanest way, which is why I would like to get this to work. Any help is greatly appreciated.

like image 938
Lukehey Avatar asked Nov 09 '15 19:11

Lukehey


People also ask

What is @AuthenticationPrincipal?

Annotation Type AuthenticationPrincipal Use AuthenticationPrincipal instead. Annotation that binds a method parameter or method return value to the Authentication. getPrincipal() . This is necessary to signal that the argument should be resolved to the current user rather than a user that might be edited on a form.

What is SecurityContextHolder getContext () getAuthentication ()?

The HttpServletRequest.getUserPrincipal() will return the result of SecurityContextHolder.getContext().getAuthentication() . This means it is an Authentication which is typically an instance of UsernamePasswordAuthenticationToken when using username and password based authentication.


2 Answers

Instead of using @AuthenticationPrincipal you can directly specify your dependency for authenticated user in method argument. something as given below

@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView index(Principal user) {
    ModelAndView mav= new ModelAndView("/web/index");
    mav.addObject("user", user);
    return mav;
} 

This Principal object will be actual object that got authenticated through spring security. Spring will inject this for you when the method will get invoked.

like image 113
Imrank Avatar answered Sep 19 '22 09:09

Imrank


In my case, I get a String back (the username) and not the UserDetails object, i.e. you should define the method signature as

public ModelAndView index(@AuthenticationPrincipal String username)

This is not strange, since @AuthenticationPrincipal in effect returns Authentication.getPrincipal() and according to the documentation:

In the case of an authentication request with username and password, this would be the username. Callers are expected to populate the principal for an authentication request.

The AuthenticationManager implementation will often return an Authentication containing richer information as the principal for use by the application. Many of the authentication providers will create a UserDetails object as the principal. See: https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/api/

So, I am assuming that your AuthenticationManager implementation is returning just a username

like image 38
user2465039 Avatar answered Sep 18 '22 09:09

user2465039