Home > Software design >  Spring Boot user is null in @AuthenticationPrincipal in Logout
Spring Boot user is null in @AuthenticationPrincipal in Logout

Time:03-09

I have a problem about getting user entity values from the authenticated process. After I sign in, I want to logout.

I have a problem to get authenticated user value as it is null.

I got this error when I logout

java.lang.NullPointerException: Cannot invoke "com.app.modal.User.getId()" because "this.user" is null

How can I fix it?

Here is my CurrentUser class shown below.

@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {

}

Here is my AuthController class shown below.

@RestController
@RequestMapping("/api/auth")
public class AuthController {

UserService userService;

RoleService roleService;

RefreshTokenService refreshTokenService;

AuthenticationManager authenticationManager;

PasswordEncoder encoder;

JwtUtils jwtUtils;

@Autowired
public AuthController(UserService userService, RoleService roleService, RefreshTokenService refreshTokenService,
                      AuthenticationManager authenticationManager, PasswordEncoder encoder, JwtUtils jwtUtils) {
    this.userService = userService;
    this.roleService = roleService;
    this.refreshTokenService = refreshTokenService;
    this.authenticationManager = authenticationManager;
    this.encoder = encoder;
    this.jwtUtils = jwtUtils;
}

@PostMapping("/signin")
    public ResponseEntity<?> authenticateUser(@RequestBody LoginRequest loginRequest) {

        LOGGER.info("AuthController | authenticateUser is started");

        String username = loginRequest.getUsername();
        String password = loginRequest.getPassword();

        LOGGER.info("AuthController | authenticateUser | username : "   username);
        LOGGER.info("AuthController | authenticateUser | password : "   password);

        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username,password);

        LOGGER.info("AuthController | authenticateUser | usernamePasswordAuthenticationToken : "   usernamePasswordAuthenticationToken.toString());

        Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal();
        String jwt = jwtUtils.generateJwtToken(userDetails);

        LOGGER.info("AuthController | authenticateUser | jwt : "   jwt);

        List<String> roles = userDetails.getAuthorities().stream().map(item -> item.getAuthority())
                .collect(Collectors.toList());

        LOGGER.info("AuthController | authenticateUser | roles : "   roles.toString());

        RefreshToken refreshToken = refreshTokenService.createRefreshToken(userDetails.getId());

        LOGGER.info("AuthController | authenticateUser | refreshToken : "   refreshToken.toString());

        JWTResponse jwtResponse = new JWTResponse();
        jwtResponse.setEmail(userDetails.getEmail());
        jwtResponse.setUsername(userDetails.getUsername());
        jwtResponse.setId(userDetails.getId());
        jwtResponse.setToken(jwt);
        jwtResponse.setRefreshToken(refreshToken.getToken());
        jwtResponse.setRoles(roles);

        LOGGER.info("AuthController | authenticateUser | jwtResponse : "   jwtResponse.toString());

        return ResponseEntity.ok(jwtResponse);
    }

@PostMapping("/logout")
    public ResponseEntity<?> logoutUser(@CurrentUser CustomUserDetails user) {

        LOGGER.info("AuthController | logoutUser is started");

        int userId = user.getId();

        int deletedValue = refreshTokenService.deleteByUserId(userId);

        if(deletedValue == 1){
            return ResponseEntity.ok(new MessageResponse("Log out successful!"));
        }else{
            return ResponseEntity.ok(new MessageResponse("You're already logout"));
        }

    }

}

Here is my CustomDetails class shown below.

public class CustomUserDetails implements UserDetails {

    private User user;

    public CustomUserDetails(User user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Set<Role> roles = user.getRoles();

        List<SimpleGrantedAuthority> authories = new ArrayList<>();

        for (Role role : roles) {
            authories.add(new SimpleGrantedAuthority(role.getName().name()));
        }

        return authories;
    }

    @Override
    public String getPassword() {
        return user.getPassword();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

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

    public String getEmail(){
        return user.getEmail();
    }
}

Here is my CustomUserDetailsService class shown below.

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = userService.findByUsername(username)
                .orElseThrow(() -> new UserNotFoundException("User Name "   username   " not found"));

        return new CustomUserDetails(user);
    }
}

Here is my WebSecurityConfig class shown below.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    CustomUserDetailsService customUserDetailsService;;

    private AuthEntryPointJwt unauthorizedHandler;

    JwtUtils jwtUtils;

    @Autowired
    public WebSecurityConfig(CustomUserDetailsService customUserDetailsService, AuthEntryPointJwt unauthorizedHandler,JwtUtils jwtUtils) {
        this.customUserDetailsService = customUserDetailsService;
        this.unauthorizedHandler = unauthorizedHandler;
        this.jwtUtils = jwtUtils;
    }

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

    @Override
    public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
                .csrf().disable()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests().antMatchers("/api/auth/**").permitAll()
                .antMatchers("/api/pages/**").permitAll()
                .anyRequest().authenticated();

        http.addFilterBefore(authenticationJwtTokenFilter(jwtUtils,customUserDetailsService), UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public AuthTokenFilter authenticationJwtTokenFilter(JwtUtils jwtUtils, CustomUserDetailsService customUserDetailsService) {
        return new AuthTokenFilter(jwtUtils, customUserDetailsService);
    }
}

CodePudding user response:

Just one change based on your repo : https://github.com/Rapter1990/SpringBootRefreshTokenJWT

  1. AuthController.java
import java.security.Principal;
import springfox.documentation.annotations.ApiIgnore;
...
@PostMapping("/logout")
    public ResponseEntity<?> logoutUser(@ApiIgnore Principal principalUser) {

        LOGGER.info("AuthController | logoutUser is started");

        //Since in AuthFilter You are setting UsernamePasswordAuthenticationToken, we will retrieve and cast
        Object principal = ((UsernamePasswordAuthenticationToken) principalUser).getPrincipal();
        CustomUserDetails user = (CustomUserDetails) principal;

        int userId = user.getId();

        int deletedValue = refreshTokenService.deleteByUserId(userId);

        if(deletedValue == 1){
            return ResponseEntity.ok(new MessageResponse("Log out successful!"));
        }else{
            return ResponseEntity.ok(new MessageResponse("You're already logout"));
        }

    }


  • Related