Spring Security in a multi module Maven project (where to put DB auth, UserDetails, etc.?)
Asked Answered
H

1

11

At the moment we have 6 Maven modules:

  • webapp
  • security
  • core (provides database access to User)
  • common
  • module1
  • module2

The dependency tree is pretty obvious I think:

  • webapp depends on everything
  • security depends on core
  • core depends on common
  • common depends on nothing
  • module1 depends on core and common
  • module2 depends on core, module1 and common

Now I'd like to have some BaseEntity: It should have a @PrePersist which saves the current User. Nearly every entity will use this BaseEntity. That's why every module depends on core.

And because everything depends on core, it seems logical to put this BaseEntity also in the core module. (even if I'd prefer to use common for this, but that seems impossible because of dependencies).

Now the problem occurs: To set the current User, I have to use access SecurityContextHolder.getContext().getAuthentication().getPrincipal(). But with this I would have some unwanted dependency (or am I just too nitpicking?).

The problem get's even worse, if I want to have a custom implementation of UserDetails. Where should I put it? core or security? Or is it common to just let the User entity implement UserDetails? I don't think so. The question occurs, because when authenticating a user, I have to create the UserDetails object inside the security module. And when I want to retrieve the current User I'd have to cast the getPrincipal() method to the custom UserDetails class.

I'm really confused how to leave thing loosely coupled, but also achieve everything I need for the application.

The last idea that came to my mind was about using Dependency Injection, but I don't know if it works!? (Having a currentUser Bean inside the security module and everyone else can simply get it via @Autowired MyCustomUserDetails)

So please help me getting those things right!

Thank you! :)

Hassle answered 23/7, 2013 at 23:35 Comment(1)
Hi Benjamin, Can you provide any insights on the same if you were able to achieve this in some way. Will be helpful for a lot of people out there as it still seems to be a active issue which many people are facing and not finding a solution.Underfur
A
0

First, it is possible to have the code that injects the current user into BaseEntity to be in a different module (that the core module does not depend on), by putting the @PrePersist method in a separate listener class. To avoid adding the @EntityListeners annotation to the entity class (and therefore adding a dependency), you could configure the listener through XML. See this answer.

Second, it appears to be quite a hassle to have dependencies injected into an entity listener, as explained here. Therefore, I would simply stick to

SecurityContextHolder.getContext().getAuthentication().getPrincipal()

Since this code can be in the security module, I think it's not a big deal. If you worry about the cast to UserDetails, you could instead call getAuthentication().getName(), which directly returns the name of the principal (if available) and use that to look up the current user in the DB.

Finally, regarding letting User implement UserDetails: Of course, doing this will add a dependency to Spring Security again, so if you want to avoid that, then don't do it. Otherwise, I don't see any major issues with it, other than having methods in your class that you may not need (isAccountNonExpired, isAccountNonLocked...) and needing to cast to User when retrieving the principal. The advantage would be that you don't need to retrieve the user from the DB first.

Abstergent answered 18/11, 2021 at 13:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.