I would like to know how to correctly store and retrieve my user in the session via Spring Security. I am using an AuthenticationManager. So far I am using the following approach which I know isn't the cleanest
public class UserController {
#Autowired
private UserService userService;
#RequestMapping(value="/myAccount", method=RequestMethod.GET)
public void myAccount(HttpServletRequest request){
//Verify Logged in user
User user = null;
UserProfile loggedinUser = (UserProfile) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if(loggedinUser != null){
user = userService.loadUserByUsername(loggedinUser.getUsername());
}
//Store User in session
Session session = request.getSession(true);
session.setAttribute("user", user);
}
}
I took a look at the answer here: Set User Object in session using Spring
But I don't fully understand how I should implement it. Could I possibly implement my User class like this
public class User implements UserDetails {
private String username;
private String password;
private String email;
......
}
And then modify my controller like this
public class UserController {
#Autowired
private UserDetailsService userDetailsService;
#RequestMapping(value="/myAccount", method=RequestMethod.GET)
public void myAccount(){
User user = (User)SecurityContextHolder.
getContext().getAuthentication().getPrincipal();
}
}
From my understanding, Spring will automatically load my custom User from the database and store it in the session?
Thanks
Related
In the applicationContext file I have added the package to map it.
The call arrives, but the variable is still null and does not pass to the server. In other classes, the same is working correctly.
Thanks in advance!
#ManagedBean(name="registerUser")
#SessionScoped
public class RegisterUser{
#ManagedProperty("#{userService}")
private DAOUser userService;
private User user = new User();
public DAOUser getUserService() {
return userService;
}
public void setUserService(DAOUser userService) {
this.userService = userService;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String register() {
// Calling Business Service
String passwordEncripada = PasswordControl.encriptString(user.getPassword());
user.setPassword(passwordEncripada);
userService.register(user);
// Add message
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage("Registro realizado"));
return "";
}
and DAOUser class:
#Component
public class DAOUser implements Serializable {
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
#Transactional
public void register(User user){
// Acquire session
Session session = sessionFactory.getCurrentSession();
// Save employee, saving behavior get done in a transactional manner
session.save(user);
}
}
EDIT: The setter is called, but the object it sends is null
I think the problem was in the normalization of the DAOUser class name. I have gone to use #Repository ("userService") instead of #Component and it is already working.
#Repository("userService")
public class DAOUser implements Serializable {
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
#Transactional
public void register(User user){
// Acquire session
Session session = sessionFactory.getCurrentSession();
// Save employee, saving behavior get done in a transactional manner
session.save(user);
}
}
What's the best approach to avoid repeating the same userService DB lookup over and over again in my controller methods?
I'm using Spring Boot 1.5.2 with spring-boot-starter-security and spring-boot-starter-thymeleaf for templating.
I tried adding an instance variable for SecurityContextHolder.getContext().getAuthentication() but it gave me a NullPointerException.
#Controller
public class DashboardController {
#Autowired
private UserService userService;
#Value("${product.name}")
private String productName;
#RequestMapping(value="/dashboard", method = RequestMethod.GET)
public ModelAndView home() {
ModelAndView modelAndView = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
modelAndView.addObject("email", user.getEmail());
modelAndView.setViewName("dashboard");
return modelAndView;
}
#RequestMapping(value="/dashboard/faq", method = RequestMethod.GET)
public ModelAndView faq(){
ModelAndView modelAndView = new ModelAndView();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = userService.findUserByEmail(auth.getName());
modelAndView.addObject("email", user.getEmail());
modelAndView.addObject("productname", productName);
modelAndView.setViewName("faq");
return modelAndView;
}
If you want to get at the user that is stored in the session, you can use this annotation:
#RequestMapping("/me")
public User me(#AuthenticationPrincipal User user) {
return user;
}
If you then want the user to always be available in thymeleaf I would use a #ControllerAdvice
#ControllerAdvice(annotations = Controller.class)
public class GlobalVariablesControllerAdvice {
#ModelAttribute("user")
public User user() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
User user = null;
// get user from authentication, but make sure to check for nulls
return user;
}
}
I am not so into Spring Security. I am working on a Spring Boot project (implementing some REST web sercices) where someone else have implemented Spring Security to perform authentication. It seems works fine but I have some doubts about how it exactly works (the architecture).
So basically I have the following classes:
1) User that is my model class representing a user:
#Entity
#Table(name = "user",
uniqueConstraints = {
#UniqueConstraint(columnNames = {"email","username"})
})
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//#Pattern(regexp="\\b[A-Z0-9._%+-]+#[A-Z0-9.-]+\\.[A-Z]{2,4}\\b",flags = Pattern.Flag.CASE_INSENSITIVE)
#Column(name="email", unique=true,nullable=false)
private String email;
#NotNull
#Column(name="registration_date",nullable=false)
private Date registration_date;
#NotBlank
#Column(name="username",nullable = false,unique=true)
private String username;
#NotBlank
#Column(name="password",nullable = false)
private String password;
#Column(name="enabled", nullable = false)
private boolean enabled;
#ManyToMany
#JoinTable(name = "user_user_roles", joinColumns = {
#JoinColumn(name = "id_user", updatable = true) },
inverseJoinColumns = { #JoinColumn(name = "id_roles",
updatable = true)},
uniqueConstraints={#UniqueConstraint(columnNames = {"id_user","id_roles"})}
)
#Cascade({CascadeType.DETACH,CascadeType.MERGE,CascadeType.REFRESH,CascadeType.PERSIST,
CascadeType.SAVE_UPDATE})
private List<UserRole> userRoles;
// CONSTRUCTOR, GETTER AND SETTER METHODS
}
It is an hibernate class that provide the join with the user_user_roles database table containing the list of user rool associated to the specific user (I think the ROLE_ADMIN, ROLE_USER, etcetc)
2) Then I have CustomUserDetails class that extends User and implements Spring Security UserDetails interface.
So it means that will contain all the information related to a specific user (among which the role associated to this user) and implement all the methods declared in the UserDetails interface.
public class CustomUserDetails extends User implements UserDetails {
private static final long serialVersionUID = 1L;
public CustomUserDetails(User user){
super(user);
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
for(UserRole role : this.getUserRoles() ){
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(role.getName());
authorities.add(grantedAuthority);
}
return authorities;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
#Override
public String getUsername() {
return super.getUsername();
}
}
It seems to me that this class represent the bridge between Spring application and Spring Security (something like that carry the roles information related to a specific user, is it?).
In this class the information related to the list of roles of an user is contained into a collection of generic object that extends GrantedAuthority.
I think that the GrantedAuthority objects represents the roles of a user (infact are builded by role.getName() that is the string representing a role of the current user). Is it this reasoning correct?
Basically the prvious implementation only return the collection of GrantedAuthority related to a specific user, is it?
3) The CustomUserDetailsService class implementing Spring Security UserDetailsService interface:
#Transactional
#Service("customUserDetailsService")
public class CustomUserDetailsService implements UserDetailsService{
#Autowired
private UserDAO userDao;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findByUsername(username);
if(user == null){
throw new UsernameNotFoundException("No user present with username: "+username);
}else{
return new CustomUserDetails(user);
}
}
}
Basically this is a service that only implements the loadUserByUsername(String username)) method that do:
First retrieve the information related the user (a User object) including the list of his roles (List userRoles).
Then use this User object to build the previous CustomUserDetails used to retrieve the collection of the GrantedAuthority related to the user.
Is all these reasoning correct?
Then I also have this WebSecurityConfig that I think represent the Spring Security configuration:
#Configuration
#EnableWebSecurity
#ComponentScan(basePackageClasses = CustomUserDetailsService.class)
#EnableAutoConfiguration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
}
}
This is pretty obsucre for me. What exactly does?
From what I have understand it is enabling the REST web services security by ** #EnableWebSecurity**.
But why does the autowire of the UserDetailsService bean?
And what exactly foes this empty configure() method?
Your reasoning is correct.
Spring-security requires you to create a service which implements UserDetailsService. It expects service to have loadUserByUsername method which returns user object (which needs to implement Spring's User class). This instance of user is used to get authorities so that you can restrict access to certain urls. i.e. you can map url access to users with specific authorities.
In terms of the empty method configure(), it is used to for authentication and authorisation of the urls (mentioned above) and few more things. In fact, in terms of security, this is most flexible & powerful method available.
My project's config method looks like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/","/static/**").permitAll()
.mvcMatchers("/admin").access("hasAuthority('ROLE_ADMIN')")
.mvcMatchers("/employees").access("hasAuthority('ROLE_STAFF')")
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.logout().logoutSuccessUrl("/")
.and()
.headers().contentSecurityPolicy("default-src 'self' " +
"https://ajax.googleapis.com " +
"https://cdnjs.cloudfare.com " +
"style-src 'self' 'unsafe-inline' ");
}
The above example
Ensures all requests are authenticated and authorized.
Permits free access to static resources
Ensures url /admin is accessible only by users with role ADMIN
Setup basic login prompt for authentication
Sets logout url
Sets up cookie based CSRF token system
Sets content security policy
To understand more about all spring-security features, I highly recommend these resources.
excellent video presentations from Rob Winch (lead on Spring Security project)
Site with good examples
Sample code repo
I have a question as to how this service and its DAO object are performing persistence transactions.
The service is performing transactions on the database - but it is not using a DAOImpl object - it is instead using an object which is an instance of the interface - and naturally has no implementation of any method signatures. This, in my mind, should not be able to perform any meaningful actions. Am I overlooking something here?
Full link to code
http://www.byteslounge.com/tutorials/spring-with-hibernate-persistence-and-transactions-example
#Service
public class UserManagerImpl implements UserManager {
#Autowired
private UserDAO userDAO;
#Override
#Transactional
public void insertUser(User user) {
userDAO.insertUser(user);
}
#Override
#Transactional
public User getUserById(int userId) {
return userDAO.getUserById(userId);
}
#Override
#Transactional
public User getUser(String username) {
return userDAO.getUser(username);
}
#Override
#Transactional
public List<User> getUsers() {
return userDAO.getUsers();
}
}
public interface UserDAO {
void insertUser(User user);
User getUserById(int userId);
User getUser(String username);
List<User> getUsers();
}
#Service
public class UserDAOImpl implements UserDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void insertUser(User user) {
sessionFactory.getCurrentSession().save(user);
}
#Override
public User getUserById(int userId) {
return (User) sessionFactory.
getCurrentSession().
get(User.class, userId);
}
#Override
public User getUser(String username) {
Query query = sessionFactory.
getCurrentSession().
createQuery("from User where username = :username");
query.setParameter("username", username);
return (User) query.list().get(0);
}
#Override
#SuppressWarnings("unchecked")
public List<User> getUsers() {
Criteria criteria = sessionFactory.
getCurrentSession().
createCriteria(User.class);
return criteria.list();
}
}
first of all , instance of an interface can not be created , reference variable can be created for interfaces. Nevertheless ,as i followed the link and found that you are learning Spring with Hibernate. Spring provide you a facility called Dependency Injection which is why there is #Autowire annotation in your UserManagerImpl class which means you have injected a dependency UserDAO in UserManagerImpl class , so on rum time ,spring will provide the instance of the class which implements UserDAO interface .What you are overlooking is thorough study of Spring concepts.by the way all the best .
I'm having this problem with passing on data between JSF beans.. What I want to do is when I login, pass the username to a next bean where I can use it. I have found many things about this but I can't get it to work in my project. What I've got is a UserService where I can manage my users. There's a method in here called getUsers(username). Now I'm trying to pass the username so I can retrieve my user-object.
xHtml:
<h:link outcome="changeProfile" value="Change profile">
<f:param name="username" value="#{userBean.username}" />
</h:link>
changeProfileBean:
#Component("changeProfile")
#ManagedBean
#RequestScoped
public class ChangeProfileBean implements Serializable {
private UserService userService;
private User user;
#ManagedProperty("#{param.username}")
private String username;
#PostConstruct
public void init(){
FacesContext facesContext = FacesContext.getCurrentInstance();
this.username = facesContext.getExternalContext().getRequestParameterMap().get("username");
try {
if(username != null){
user = userService.getUser(username);
}
} catch (UserServiceException e) {
e.printStackTrace();
}
}
#Autowired
public ChangeProfileBean(UserService userService) {
this.userService = userService;
}
What happens is that the changeUserbean will be created when the app is starting. And immediately after that runs the #PostConstruct where username obviously equals null. But when I call the changeUserBean it doesn't execute the #PostConstruct anymore..
Does anybody know what I could do?
UserBean:
#Component("userBean")
#Scope("session")
public class UserBean implements Serializable
{
#Autowired
private UserService userService;
#Autowired
private RepairService repairService;
private String username;
private String password;
While you have already the data you need in a broader scope, just inject that backing-bean into changeProfileBean:
#ManagedBean
#RequestScoped
public class ChangeProfileBean implements Serializable {
#ManagedProperty("#{userBean}")
private UserBean userBean;
public UserBean getUserBean(){
return userBean;
}
public void setUserBean(UserBean userBean){
this.userBean = userBean;
}
...
}