我正在尝试为在移动应用程序上用Facebook登录的用户生成JWT令牌。我将facebook数据发送到此功能:

@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);
}


然后从我的attemptAuthentication类中调用JWTAuthenticationFilter

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);
}

}


但是attemptAuthentication类中的JWTAuthenticationFilter方法会引发以下错误:在以下代码行中的java.io.IOException: Stream closed

 User creds = new ObjectMapper()
                .readValue(request.getInputStream(), User.class);


如果我通过HTTP请求调用attemptAuthentication方法,它可以正常工作。什么是或可能是仅当从另一个类调用流关闭异常时才得到它的问题?

谢谢!

最佳答案

你用

@RequestBody User user


对于第一种情况,Spring框架已经处理了HttpServletRequest实例的输入流(默认情况下只能发生一次),解析数据并将user实例注入到处理程序中。

因此,在调用处理程序时将关闭输入流。您可以重载attemptAuthentication方法,并将用户实例作为参数传递。

我想您在第二种情况下没有任何Spring映射,因此输入流保持“不变”,并且您可以在身份验证方法中对其进行处理。

08-28 18:04