I using the POST method for add Item
to the database with Spring MVC. But each Item
has field userId
, it FOREIGN KEY
to users
table. Need to know user’s id for this. I using Spring security for auth. May be there is a possibility get current user’s id with ServletContext
or HttpSession
, may be spring security save user’s id somewhere?
How to identify user which requested to the server with Spring MVC to data in the database?
@PostMapping("/get_all_items/add_item_page/add_item") public String addItem(@RequestParam(value = "description") final String description) { final Item item = new Item(); item.setDescription(description); item.setAuthorId(/* ??? */); service.add(item); return "redirect:get_all_items"; }
Spring security implementation with using UserDetails
so all details hidden from me, and I don’t know how to intervene in auth process and intercept user’s id in the authorysation stage.
@Entity(name = "users") public class User implements UserDetails {...} @Autowired private UserService userService; @Autowired private void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService); }
Thank You!
Advertisement
Answer
Please try with this approach
Make sure that you have your own User
pojo class
@Entity public class MyUser { @Id private Long id; private String username; private String password; private boolean isEnabled; @ManyToMany private List<MyAuthority> myAuthorities; ... }
Also an Authority
pojo in order to define the user roles
@Entity public class MyAuthority { @Id private int id; private String name; .....
Then the user repository, in this example I just declare a method to find by username and get an Optional to validate if the user exists.
public interface MyUserRepository extends CrudRepository<MyUser,Long> { public Optional<MyUser> findFirstByUsername(String username); }
Create a user class that extends from org.springframework.security.core.userdetails.User
in order to wrap your custom user inside the definition of the spring security user.
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import java.util.Collection; public class MySpringUser extends User { private MyUser user; public MySpringUser(MyUser myUser, Collection<? extends GrantedAuthority> authorities) { super(myUser.getUsername(), myUser.getPassword(), myUser.isEnabled() , true, true, true, authorities); this.setUser(myUser); } public MyUser getUser() { return user; } public void setUser(MyUser user) { this.user = user; } }
And now the UserDetailService
implementation, there is just one method to implement loadUserByUsername
here is where the MyUserRepository
is needed, in order to retrieve the user information from the repository by the username.
@Service public class MyUserService implements UserDetailsService { @Autowired MyUserRepository myUserRepository; @Override public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { Optional<MyUser> myUser = myUserRepository.findFirstByUsername(s); return myUser.map( (user) -> { return new MySpringUser( user, user.getMyAuthorities().stream(). map( authority -> new SimpleGrantedAuthority(authority.getName())). collect(Collectors.toList())); }).orElseThrow(() -> new UsernameNotFoundException("user not found")); } }
And now you can inject the UserDetailService
because its implementation will be injected form MyUserService
class.
@Autowired private UserService userService; @Autowired private void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userService); }
then with this approach you can inject the Principal
object to your controller, and inside the method you can cast the Principal
object to MySpringUser
, it is because MySpringUser
is extended from org.springframework.security.core.userdetails.User
and User class implements the UserDetails
interface. Of course you can get all the rest of custom fields of the user because its definition is wrapped inside the org.springframework.security.core.userdetails.User
class
@PostMapping("/get_all_items/add_item_page/add_item") public String addItem(@RequestParam(value = "description") final String description, Principal principal) { MySpringUser mySpringUser = (MySpringUser)principal; final Item item = new Item(); item.setDescription(description); item.setAuthorId(mySpringUser.getUser().getId()); service.add(item); return "redirect:get_all_items"; }