I am trying to generate a JWT token for a user who has logged in with Facebook on the mobile app. I send the facebook data to this function:
@PostMapping("/facebook")
public void registerWithFacebook(@RequestBody User user, HttpServletRequest request, HttpServletResponse response){
User loggingInUser = this.userRepository.findByUsername(user.getUsername());
if( loggingInUser == null){
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
user.setBlocked(false);
this.userRepository.save(user);
}
//Generate JWT token for user
JWTAuthenticationFilter jwtAuthenticationFilter = new JWTAuthenticationFilter(this.authenticationManager, this.userRepository);
jwtAuthenticationFilter.attemptAuthentication(request, response);
}
And I call the attemptAuthentication
from my JWTAuthenticationFilter
class:
public class JWTAuthenticationFilter extends
UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
private UserRepository userRepository;
public JWTAuthenticationFilter() {
}
public JWTAuthenticationFilter(AuthenticationManager authenticationManager, UserRepository userRepository) {
this.authenticationManager = authenticationManager;
this.userRepository = userRepository;
setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/api/login", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
try {
User creds = new ObjectMapper()
.readValue(request.getInputStream(), User.class);
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
new ArrayList<>())
);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
String token = Jwts.builder()
.setSubject(((org.springframework.security.core.userdetails.User) authResult.getPrincipal()).getUsername())
.setExpiration(new Date(System.currentTimeMillis() + SecurityConstants.EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS512, SecurityConstants.JWT_SECRET.getBytes())
.compact();
response.addHeader(SecurityConstants.HEADER_STRING, token);
String username = JWTAuthorizationFilter.getUsernameFromToken(token);
User user = this.userRepository.findByUsername(username);
Map<String, String> responseBody = new HashMap<>();
responseBody.put("token", token);
responseBody.put("blocked", Boolean.toString(user.isBlocked()));
responseBody.put("paid", Boolean.toString(user.isPaid()));
responseBody.put("endSubscription", user.getEndSubscribtionDate() + "");
String jsonResponse = new ObjectMapper().writeValueAsString(responseBody);
response.getWriter().write(jsonResponse);
}
}
But the attemptAuthentication
method from JWTAuthenticationFilter
class throws the following error: java.io.IOException: Stream closed
in the following line of code :
User creds = new ObjectMapper()
.readValue(request.getInputStream(), User.class);
If I call the attemptAuthentication
method through HTTP request, it works fine. What is or may be the problem that I get the stream closed exception ONLY when it is called from another class?
Thank you!
2
Answers
You use
for first case, so Spring framework already processed input stream of
HttpServletRequest
instance (can happen only once by default), parsed data and injecteduser
instance to your handler.So input stream is closed when handler is called. You can overload
attemptAuthentication
method and pass user instance as a param instead.I suppose you don’t have any Spring mappings for second case, so input stream stays “untouched” and you are able to process it within the authentication method.
I know this answer is super late but its for people that might have this problem in the future.
If you did everything that udalmik said and you still have the problem double check that you annotated your UserDetailsServiceImpl class as a @Service.
yep it took me 4 hours to figure that out I did not annotate my class.