Jill
Jill

Reputation: 441

How can I display the current logged in User with Spring Boot Thymeleaf?

I am trying to display the details of the current user however I keep getting errors. I tried accessing the authenticated user from the template but that did not work as I was getting this error:

Method getFirstName() cannot be found on org.springframework.security.core.userdetails.User type

I was trying to get the information from a controller and then saving it in a string and passsing the string to a template but that wasn't working either.

Here is my SecurityConfig class:

    @Configuration
 public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserService userService;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
                .antMatchers(
                        "/registration",
                        "/js/**",
                        "/css/**",
                        "/img/**",
                        "/webjars/**").permitAll()
                .anyRequest().authenticated()
            .and()
                .formLogin()
                    .loginPage("/login")
                        .permitAll()
            .and()
                .logout()
                    .invalidateHttpSession(true)
                    .clearAuthentication(true)
                    .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
                    .logoutSuccessUrl("/login?logout")
            .permitAll();
}

@Bean
public BCryptPasswordEncoder passwordEncoder(){
    return new BCryptPasswordEncoder();
}

@Bean
public DaoAuthenticationProvider authenticationProvider(){
    DaoAuthenticationProvider auth = new DaoAuthenticationProvider();
    auth.setUserDetailsService(userService);
    auth.setPasswordEncoder(passwordEncoder());
    return auth;
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider());

}

Here is my UserService Class:

 public interface UserService extends UserDetailsService {

User findByEmailAddress(String emailAddress);
  //  User findByFirstName(String firstName);

User save(UserRegistrationDto registration);
}

Here is my UserServiceImpl class:

 @Service
public class UserServiceImpl implements UserService {

@Autowired
private UserRepository userRepository;

@Autowired
private BCryptPasswordEncoder passwordEncoder;

@Override
public UserDetails loadUserByUsername(String emailAddress) throws 
UsernameNotFoundException {
    User user = userRepository.findByEmailAddress(emailAddress);
    if (user == null){
        throw new UsernameNotFoundException("Invalid username or 
password.");
    }
    return new 
org.springframework.security.core.userdetails.User(user.getEmailAddress(),
            user.getPassword(),
            mapRolesToAuthorities(user.getRoles()));
}

public User findByEmailAddress(String emailAddress){
    return userRepository.findByEmailAddress(emailAddress);
}

public User save(UserRegistrationDto registration){
    User user = new User();
    user.setFirstName(registration.getFirstName());
    user.setSurname(registration.getSurname());
    user.setEmailAddress(registration.getEmailAddress());
    user.setPassword(passwordEncoder.encode(registration.getPassword()));
    user.setRoles(Arrays.asList(new Role("ROLE_USER")));
    return userRepository.save(user);
}

private Collection<? extends GrantedAuthority> 
mapRolesToAuthorities(Collection<Role> roles){
    return roles.stream()
            .map(role -> new SimpleGrantedAuthority(role.getName()))
            .collect(Collectors.toList());
}


}

Here is some code from the template class where I'm trying to get the information:

th:text ="${#authentication.getPrincipal().getFirstName()}">

th:text ="${#authentication.getPrincipal().getUser().getFirstName()}">

This is the login controller. The parts I have commented out was another way I was trying to get the current users details:

@Controller
//@RequestMapping("/login")
public class MainController {

//    @GetMapping("/")
//    public String root() {
//        return "userProfile1";
//    }

@GetMapping("/login")
public String login(Model model) {
    return "login";

}

 //   @GetMapping
  //  public String displayUserAccount(@ModelAttribute("user") @Valid             
UserRegistrationDto userDto, BindingResult result, Model model) {
//    
// 
//      model.addAttribute("firstName", ((UserRegistrationDto)         
auth).getEmailAddress());
//      
//      model.addAttribute("emailAddress", userDto.getEmailAddress());
//        model.addAttribute("firstName", userDto.getFirstName());
//        model.addAttribute("surname", userDto.getSurname());
//        model.addAttribute("age", userDto.getAge());
//        model.addAttribute("gender", userDto.getGender());
//        model.addAttribute("dob", userDto.getDob());
//       // return "redirect:/registration?success";
  //  return "userProfile1";
//      
  //  }

@ResponseBody
public String currentUserName(Authentication auth) {
    ((UserRegistrationDto) auth).getEmailAddress();
    return  "userProfile1";


}


  } 

This is all over the place I'm sorry! Thanks so much for anyone who helps :D

Upvotes: 5

Views: 15516

Answers (5)

Bu Saeed
Bu Saeed

Reputation: 1337

You can get the username attribute easily from your Principal class.

@GetMapping(value = "/")
    public String index(@AuthenticationPrincipal MyUserPrincipal principal) {
        String username = principal.getUsername();
        //Do whatever you want here
        return "index";
    }

However, if you want more details than the ones inside Principal class then you need to explicitly define them in your principal class:

public int getId() {
    return member.getId();
}

So now you can invoke it directly:

@GetMapping(value = "/")
    public String index(@AuthenticationPrincipal MyUserPrincipal principal) {
        int userId = principal.getId();
        //Do whatever you want here
        return "index";
    }

You will need to import the following:

import org.springframework.security.core.annotation.AuthenticationPrincipal;

If you only want to get a Principal class attribute directly from Thymeleaf then you can alternatively do the following:

<span sec:authentication="principal.username">Username</span>

Upvotes: 0

Reference (4. Spring Security Dialect):

https://www.thymeleaf.org/doc/articles/springsecurity.html

Add dependencies pom.xml

<dependency>
        <groupId>org.thymeleaf.extras</groupId>
        <artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>

and the view (Thymeleaf):

<div sec:authorize="isAuthenticated()"> 
    Authenticated user roles:
    Logged user: <span sec:authentication="name"></span> |
    Roles: <span sec:authentication="principal.authorities"></span>
</div>

I hope you serve them

Upvotes: 1

Hasitha Diluka
Hasitha Diluka

Reputation: 776

You can use Thymeleaf extras for display authenticated user details.

Thymeleaf Extras Springsecurity4

    <div th:text="${#authentication.name} ></div>

Upvotes: 10

Jill
Jill

Reputation: 441

I figured out how to fix my problem.

I created this method in a controller:

  @Autowired
UserRepository userR;
@GetMapping
public String currentUser(@ModelAttribute("user") @Valid UserRegistrationDto userDto, BindingResult result, Model model) {

    Authentication loggedInUser = SecurityContextHolder.getContext().getAuthentication();
    String email = loggedInUser.getName(); 

     User user = userR.findByEmailAddress(email);
    String firstname = user.getFirstName();
     model.addAttribute("firstName", firstname);
    model.addAttribute("emailAddress", email);

    return "userProfile1"; //this is the name of my template
}

and then I added this line of code in my html template:

Email: th:text="${emailAddress}"

Upvotes: 1

holmis83
holmis83

Reputation: 16644

The problem is here:

return new 
org.springframework.security.core.userdetails.User(user.getEmailAddress(),
        user.getPassword(),
        mapRolesToAuthorities(user.getRoles()));

You lose the reference to your User entity. Change it to:

return user;

For this to work, you need to update your User entity to implement UserDetails interface:

public class User implements UserDetails {
    // some new methods to implement
}

Then, your Thymleaf code should work. Another way of getting the firstName would be:

<span th:text="${#request.userPrincipal.principal.firstName}"></span>

Upvotes: 3

Related Questions