title: Spring with JWT auth, get current user
body: <p>I have Spring Boot REST application which uses JWT tokens for authorization. I want to get current logged user in controllers using <code>@AuthenticationPrincipal</code> annotation. But it always returns <code>null</code> if i return custom model from <code>loadUserByUsername</code> and auth stop working. My model implements <code>UserDetails</code>.</p>
  
  <p>I tried to extend the <code>org.springframework.security.core.userdetails.User</code> but i get rid errors from <strong>JWTAuthenticationFilter</strong> that default constructor not exists (<code>ApplicationUser creds = new ObjectMapper().readValue(req.getInputStream(), ApplicationUser.class);</code>)</p>
  
  <p>Whats wrong?</p>
  
  <p><strong>UserDetailsServiceImpl.java</strong></p>
  
  <pre><code>@Service
  public class UserDetailsServiceImpl implements UserDetailsService {
      private UserRepository userRepository;
  
      public UserDetailsServiceImpl(UserRepository userRepository) {
          this.userRepository = userRepository;
      }
  
      @Override
      public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
          ApplicationUser applicationUser = userRepository.findByUsername(username);
          if (applicationUser == null) throw new UsernameNotFoundException(username);
  
          return applicationUser;
      }
  }
  </code></pre>
  
  <p><strong>ApplicationUser.java (model)</strong></p>
  
  <pre><code>@Entity
  @Table(name = "users")
  public class ApplicationUser implements UserDetails {
  
      private static final long serialVersionUID = 1L;
  
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private long id;
  
      @Column(unique = true, nullable = false)
      private String username;
  
      @Column(unique = true, nullable = false)
      private String email;
  
      @Column(nullable = false)
      private String password;
  
      public long getId() {
          return id;
      }
  
      public void setId(long id) {
          this.id = id;
      }
  
      public String getUsername() {
          return username;
      }
  
      public void setUsername(String username) {
          this.username = username;
      }
  
      public String getEmail() {
          return email;
      }
  
      public void setEmail(String email) {
          this.email = email;
      }
  
      public String getPassword() {
          return password;
      }
  
      public void setPassword(String password) {
          this.password = password;
      }
  
      @Override
      public boolean isAccountNonExpired() {
          return false;
      }
  
      @Override
      public boolean isAccountNonLocked() {
          return false;
      }
  
      @Override
      public boolean isCredentialsNonExpired() {
          return false;
      }
  
      @Override
      public boolean isEnabled() {
          return false;
      }
  
      @Override
      public Collection&lt;? extends GrantedAuthority&gt; getAuthorities() {
          return null;
      }
  }
  </code></pre>
  
  <p><strong>JWTAuthenticationFilter</strong></p>
  
  <pre><code>public class JWTAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
      private AuthenticationManager authenticationManager;
  
      public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
          super(new AntPathRequestMatcher(LOGIN_URL));
  
          this.authenticationManager = authenticationManager;
      }
  
      @Override
      public Authentication attemptAuthentication(HttpServletRequest req,
                                                  HttpServletResponse res) throws AuthenticationException {
          try {
              ApplicationUser creds = new ObjectMapper()
                      .readValue(req.getInputStream(), ApplicationUser.class);
  
              return authenticationManager.authenticate(
                      new UsernamePasswordAuthenticationToken(
                              creds.getUsername(),
                              creds.getPassword(),
                              new ArrayList&lt;&gt;())
              );
          } catch (IOException e) {
              throw new RuntimeException(e);
          }
      }
  
      @Override
      protected void successfulAuthentication(HttpServletRequest req,
                                              HttpServletResponse res,
                                              FilterChain chain,
                                              Authentication auth) throws IOException, ServletException {
  
          String token = Jwts.builder()
                  .setSubject(((ApplicationUser) auth.getPrincipal()).getUsername())
                  .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                  .signWith(SignatureAlgorithm.HS512, SECRET.getBytes())
                  .compact();
  
          res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
      }
  }
  </code></pre>
  
  <p><strong>JWTAuthorizationFilter</strong></p>
  
  <pre><code>public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
  
      public JWTAuthorizationFilter(AuthenticationManager authManager) {
          super(authManager);
      }
  
      @Override
      protected void doFilterInternal(HttpServletRequest req,
                                      HttpServletResponse res,
                                      FilterChain chain) throws IOException, ServletException {
          String header = req.getHeader(HEADER_STRING);
  
          if (header == null || !header.startsWith(TOKEN_PREFIX)) {
              chain.doFilter(req, res);
              return;
          }
  
          UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
  
          SecurityContextHolder.getContext().setAuthentication(authentication);
          chain.doFilter(req, res);
      }
  
      private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
          String token = request.getHeader(HEADER_STRING);
          if (token != null) {
              // parse the token.
              String user;
              try {
                  user = Jwts.parser()
                          .setSigningKey(SECRET.getBytes())
                          .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                          .getBody()
                          .getSubject();
              } catch (SignatureException e) {
                  return null;
              }
  
              if (user != null) return new UsernamePasswordAuthenticationToken(user, null, new ArrayList&lt;&gt;());
  
              return null;
          }
          return null;
      }
  }
  </code></pre>