2

I have a Spring MVC application where I'm exposing an endpoint, and a small library where I wrote some common functionality.

I have an utility class like this:

class SecurityUtil {
    public static Principal getPrincipal(){
       return SecurityContextHolder.getContext().getAuthentication()
              .getPrincipal();
    } 
}

And from the Controller I'm doing something like:

 class MyController {

      public ResponseEntity<Void> myEndpoint(){
           // do something
           Principal principal = SecurityUtil.getPrincipal();
           // use the principal information for some audit processes
      }
 }

In this case the Principal is null, but if replace my code like this:

 class MyController {

      public ResponseEntity<Void> myEndpoint(){
           // do something
           Principal principal = SecurityContextHolder.getContext()
                                                      .getAuthentication()
                                                      .getPrincipal();
           // use the principal information for some audit processes
      }
 }

In this case the Principal is not null and it has the information that I need.
Do you know what could be happening?

nondestructive
  • 134
  • 2
  • 10
Rene Enriquez
  • 1,418
  • 1
  • 13
  • 33

1 Answers1

4

I was going through the same problem and then I have solved it in following manner.

Create UserService interface

public interface UserService {
    String getLoggedInUserName();
    User getLoggedInUser();
}

Provide an implementation for UserService, However, you can also it without creating the interface and by simply creating UserService as a class.

@Service
public class UserServiceImpl implements UserService { 

    private static Log log = LogFactory.getLog(UserServiceImpl.class);

    @Override
    public String getLoggedInUserName() {
        try {
            return getLoggedInUser().getUsername();
        } catch (Exception ex) {
            throw new UsernameNotFoundException("Please Log in", ex);
        }
    }

    @Override
    public User getLoggedInUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication.getPrincipal() instanceof User) {
            return (User) authentication.getPrincipal();
        } else {
            throw new UsernameNotFoundException("User is not authenticated; Found " + authentication.getPrincipal() + " of type " + authentication.getPrincipal().getClass() + "; Expected type User");
        }
    }

}

And the calling userService.getLoggedInUserName() by auto wiring UserService

@Autowired UserService userService

Update: If you are getting them in your controller only then you can simply pass Principal principal as a method argument to your controller method instead of getting it from the security context. It will be auto-wired to controller automatically and later on you can pass it your service methods. This way is also considered a good practice Spring MVC, getting principal from security context in service layer

@RequestMapping(value = "/myEndpoint", method = GET)
public ResponseEntity<Void> myEndpoint(Principal principal){
   // do something
   // use the principal information for some audit processes
}
Naresh Joshi
  • 4,188
  • 35
  • 45
  • mmm this is not working for me either. Is UserService and UserServiceImpl in a jar? or is directly on the MVC project – Rene Enriquez Aug 18 '17 at 15:58
  • It is directly in my project, but I think having them in the jar will also not cause any problem I have tested it. – Naresh Joshi Aug 18 '17 at 17:24
  • If you are getting them in your controller only then you can simply pass `Principal principal` as a method argument to your controller method instead of getting it from security context. – Naresh Joshi Aug 18 '17 at 17:26
  • 1
    Thanks Naresh Joshi, I had an error in my application context, now it's working – Rene Enriquez Aug 22 '17 at 16:02